<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 6.3.0">
  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">


<link rel="stylesheet" href="/lib/font-awesome/css/all.min.css">

<script id="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"chuangges.gitee.io","root":"/","scheme":"Pisces","version":"7.8.0","exturl":false,"sidebar":{"position":"right","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":true,"show_result":true,"style":"mac"},"back2top":{"enable":true,"sidebar":false,"scrollpercent":false},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":false,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},"path":"search.xml"};
  </script>

  <meta name="description" content="项目构建、组件开发、表单控件、HTTP 请求、Router 路由">
<meta property="og:type" content="article">
<meta property="og:title" content="Angular 项目开发">
<meta property="og:url" content="https://chuangges.gitee.io/2020/09/09/14-1-angular%E5%9F%BA%E7%A1%80/index.html">
<meta property="og:site_name" content="闯哥要去流浪了">
<meta property="og:description" content="项目构建、组件开发、表单控件、HTTP 请求、Router 路由">
<meta property="og:locale" content="zh_CN">
<meta property="article:published_time" content="2020-09-09T03:13:35.000Z">
<meta property="article:modified_time" content="2022-09-30T08:35:22.330Z">
<meta property="article:author" content="chuangges">
<meta property="article:tag" content="JS 框架">
<meta name="twitter:card" content="summary">

<link rel="canonical" href="https://chuangges.gitee.io/2020/09/09/14-1-angular%E5%9F%BA%E7%A1%80/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : false,
    isPost : true,
    lang   : 'zh-CN'
  };
</script>

  <title>Angular 项目开发 | 闯哥要去流浪了</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

<link rel="alternate" href="/atom.xml" title="闯哥要去流浪了" type="application/atom+xml">
</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <h1 class="site-title">闯哥要去流浪了</h1>
      <span class="logo-line-after"><i></i></span>
    </a>
      <p class="site-subtitle" itemprop="description">愿你岁月可回首，且以深情共白头</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
    </div>
  </div>
</div>




<nav class="site-nav">
  <ul id="menu" class="main-menu menu">
        <li class="menu-item menu-item-home">

    <a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a>

  </li>
  </ul>
</nav>




</div>
    </header>

    
  <div class="back-to-top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>
  <div class="reading-progress-bar"></div>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content post posts-expand">
            

    
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://chuangges.gitee.io/2020/09/09/14-1-angular%E5%9F%BA%E7%A1%80/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/chuang.png">
      <meta itemprop="name" content="chuangges">
      <meta itemprop="description" content="chuangge's blog.">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="闯哥要去流浪了">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          Angular 项目开发
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2020-09-09 11:13:35" itemprop="dateCreated datePublished" datetime="2020-09-09T11:13:35+08:00">2020-09-09</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2022-09-30 16:35:22" itemprop="dateModified" datetime="2022-09-30T16:35:22+08:00">2022-09-30</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/JS-%E6%A1%86%E6%9E%B6/" itemprop="url" rel="index"><span itemprop="name">JS 框架</span></a>
                </span>
            </span>

          <br>
            <span class="post-meta-item" title="本文字数">
              <span class="post-meta-item-icon">
                <i class="far fa-file-word"></i>
              </span>
                <span class="post-meta-item-text">本文字数：</span>
              <span>32k</span>
            </span>
            <span class="post-meta-item" title="阅读时长">
              <span class="post-meta-item-icon">
                <i class="far fa-clock"></i>
              </span>
                <span class="post-meta-item-text">阅读时长 &asymp;</span>
              <span>29 分钟</span>
            </span>
            <div class="post-description">项目构建、组件开发、表单控件、HTTP 请求、Router 路由</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
        <h1 id="一、项目构建"><a href="#一、项目构建" class="headerlink" title="一、项目构建"></a>一、项目构建</h1><ul>
<li><strong>独立开发者</strong>：利用 cli 可以简单的创建 Angular 应用程序、组件和其他模块，Standalone 无需很多模板也可以轻松创建组件。</li>
<li><strong>初创公司</strong>：利用 Angular Language Service 插件，开发人员可以生成一致的代码，通过类型检测和其他工具，开发人员可以在部署前发现错误。</li>
<li><strong>中型公司</strong>：Angular 目前已经支持国际化和渐进式 Web 应用程序(PWA)。</li>
<li><strong>大型公司</strong>：微前端。</li>
</ul>
<h2 id="项目新建"><a href="#项目新建" class="headerlink" title="项目新建"></a>项目新建</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 安装：当前 angular@14</span></span><br><span class="line">cnpm i -g @angular/cli</span><br><span class="line"></span><br><span class="line"><span class="comment">// 跳过依赖安装、覆盖现有文件、更严格的 typescript 编译选项</span></span><br><span class="line">ng <span class="keyword">new</span> my-app --skip-install、--force、--strict</span><br><span class="line">ng test、ng e2e            <span class="comment">// 单元测试、端对端测试</span></span><br><span class="line">ng serve、ng build         <span class="comment">// 运行、打包</span></span><br><span class="line">ng serve -o/--open         <span class="comment">// 打开浏览器</span></span><br><span class="line">ng serve --prod            <span class="comment">// 开发环境运行</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 新建类、接口、组件、指令、服务、模块、管道、枚举</span></span><br><span class="line">ng g <span class="keyword">class</span> <span class="title class_">model</span>/name</span><br><span class="line">ng g interface model/hero</span><br><span class="line">ng g component components/name</span><br><span class="line">ng g directive directives/name</span><br><span class="line">ng g service services/name</span><br><span class="line">ng g <span class="variable language_">module</span> name</span><br><span class="line">ng g pipe name</span><br><span class="line">ng g enum name</span><br></pre></td></tr></table></figure>


<h2 id="目录解析"><a href="#目录解析" class="headerlink" title="目录解析"></a>目录解析</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 运行时文件加载顺序</span></span><br><span class="line">main.<span class="property">ts</span>、app.<span class="property">module</span>.<span class="property">ts</span>、app.<span class="property">component</span>.<span class="property">ts</span>、index.<span class="property">html</span>、app.<span class="property">component</span>.<span class="property">html</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 项目目录 </span></span><br><span class="line">├── e2e            <span class="comment">// 端对端测试文件</span></span><br><span class="line">├── config.<span class="property">xml</span>     <span class="comment">// 打包成 app 的配置文件</span></span><br><span class="line">├── package.<span class="property">json</span>   <span class="comment">// 配置项目的元数据和管理项目所需要的依赖</span></span><br><span class="line">├── angular.<span class="property">json</span>   <span class="comment">// angular 配置文件</span></span><br><span class="line">├── karma.<span class="property">conf</span>.<span class="property">js</span>  <span class="comment">// 测试相关的配置文件</span></span><br><span class="line">├── tsconfig.<span class="property">json</span>  <span class="comment">// 指定编译 typescript 项目的根文件和编译选项</span></span><br><span class="line">├── tslint.<span class="property">json</span>    <span class="comment">// 格式化和校验 typescript</span></span><br><span class="line">└── src：          <span class="comment">// 工作空间源代码</span></span><br><span class="line">    ├── app           <span class="comment">// 应用根目录（组件、路由、静态资源等）</span></span><br><span class="line">    ├── environments  <span class="comment">// 环境配置</span></span><br><span class="line">    ├── favicon.<span class="property">ico</span>   <span class="comment">// 网站图标</span></span><br><span class="line">    ├── index.<span class="property">html</span>    <span class="comment">// 应用的主页面</span></span><br><span class="line">    ├── styles.<span class="property">scss</span>   <span class="comment">// 全局样式文件</span></span><br><span class="line">    ├── main.<span class="property">ts</span>       <span class="comment">// 主入口文件</span></span><br><span class="line">    ├── test.<span class="property">js</span>       <span class="comment">// 测试入口文件</span></span><br><span class="line">    └── polyfills.<span class="property">ts</span>  <span class="comment">// 兼容不同浏览器</span></span><br></pre></td></tr></table></figure>


<h2 id="模块引用"><a href="#模块引用" class="headerlink" title="模块引用"></a>模块引用</h2><blockquote>
<p>内置模块主要有：核心模块 @angular&#x2F;core、通用模块 @angular&#x2F;common、表单模块 @angular&#x2F;forms、网络模块 @angular&#x2F;http。简单项目时可以将所有组件都挂载到根模块，复杂项目时则需要通过自定义模块来组织代码和实现路由懒加载。</p>
</blockquote>
  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 自定义模块：新建模块、组件、服务</span></span><br><span class="line">ng g m <span class="variable language_">module</span>/user --routing          <span class="comment">// m == module</span></span><br><span class="line">ng g s <span class="variable language_">module</span>/user/services/common    <span class="comment">// s == service</span></span><br><span class="line">ng g c <span class="variable language_">module</span>/user                    <span class="comment">// c == component、根组件</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 自定义子组件</span></span><br><span class="line">ng g c <span class="variable language_">module</span>/user/components/order</span><br><span class="line">ng g c <span class="variable language_">module</span>/user/components/address</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 路由懒加载模块</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> forRoot、forChild：分别用于根模块、子模块加载路由的 RouterModule 对象方法</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> component、loadChildren：分别用于加载模块、组件</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> loadChildren：导入模块的相对路径、\#分隔符、导出模块类的名称</span></span><br><span class="line"><span class="comment"> **/</span> </span><br><span class="line"><span class="comment">// user-routing.module.ts</span></span><br><span class="line"><span class="keyword">const</span> <span class="attr">routes</span>: <span class="title class_">Routes</span> = [</span><br><span class="line">    <span class="comment">// &lt;a [routerLink]=&quot;[&#x27;/user&#x27;]&quot;&gt;用户模块&lt;/a&gt;</span></span><br><span class="line">    &#123; </span><br><span class="line">      <span class="attr">path</span>: <span class="string">&#x27;&#x27;</span>, </span><br><span class="line">      <span class="attr">component</span>: <span class="title class_">UserComponent</span>, </span><br><span class="line">      <span class="attr">children</span>: [&#123; <span class="attr">path</span>: <span class="string">&#x27;order&#x27;</span>, <span class="attr">component</span>: <span class="title class_">OrderComponent</span> &#125;]</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="comment">// &lt;a [routerLink]=&quot;[&#x27;/user/address&#x27;]&quot;&gt;用户地址&lt;/a&gt;</span></span><br><span class="line">    &#123; <span class="attr">path</span>: <span class="string">&#x27;address&#x27;</span>, <span class="attr">component</span>: <span class="title class_">AddressComponent</span> &#125;</span><br><span class="line">]</span><br><span class="line">@<span class="title class_">NgModule</span>(&#123;</span><br><span class="line">    <span class="attr">imports</span>: [<span class="title class_">RouterModule</span>.<span class="title function_">forChild</span>(routes)],</span><br><span class="line">    <span class="attr">exports</span>: [<span class="title class_">RouterModule</span>]</span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">UserRoutingModule</span> &#123; &#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// user.module.ts</span></span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">UserComponent</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;./user.component&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">OrderComponent</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;./components/order/order.component&#x27;</span>;</span><br><span class="line">@<span class="title class_">NgModule</span>(&#123;</span><br><span class="line">    <span class="attr">declarations</span>: [<span class="title class_">UserComponent</span>, <span class="title class_">OrderComponent</span>, <span class="title class_">AddressComponent</span>],</span><br><span class="line">    <span class="attr">imports</span>: [<span class="title class_">UserRoutingModule</span>],</span><br><span class="line">    <span class="attr">exports</span>: [<span class="title class_">UserComponent</span>]       <span class="comment">// 暴露组件</span></span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">UserModule</span> &#123; &#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// app-routing.module.ts</span></span><br><span class="line"><span class="keyword">const</span> <span class="attr">routes</span>: <span class="title class_">Routes</span> = [</span><br><span class="line">    &#123; <span class="attr">path</span>: <span class="string">&#x27;home&#x27;</span>, <span class="attr">component</span>: <span class="title class_">HomeComponent</span> &#125;,</span><br><span class="line">    &#123; <span class="attr">path</span>: <span class="string">&#x27;&#x27;</span>, <span class="attr">redirectTo</span>: <span class="string">&#x27;/home&#x27;</span>, <span class="attr">pathMatch</span>: <span class="string">&#x27;full&#x27;</span> &#125;,</span><br><span class="line">    <span class="comment">// 懒加载模式一：导入模块的相对路径、#分隔符、导出模块类的名称</span></span><br><span class="line">    &#123; <span class="attr">path</span>: <span class="string">&#x27;user&#x27;</span>, <span class="attr">loadChildren</span>: <span class="string">&#x27;./module/user/user.module#UserModule&#x27;</span> &#125;,</span><br><span class="line">    &#123; <span class="attr">path</span>: <span class="string">&#x27;user&#x27;</span>, <span class="attr">loadChildren</span>: <span class="function">() =&gt;</span> <span class="title function_">import</span>(<span class="string">&#x27;./module/user/user.module&#x27;</span>)</span><br><span class="line">                                        .<span class="title function_">then</span>( <span class="function"><span class="params">m</span> =&gt;</span> m.<span class="property">UserModule</span>) &#125;,</span><br><span class="line">];</span><br><span class="line">@<span class="title class_">NgModule</span>(&#123;</span><br><span class="line">    <span class="attr">imports</span>: [<span class="title class_">RouterModule</span>.<span class="title function_">forRoot</span>(routes)],</span><br><span class="line">    <span class="attr">exports</span>: [<span class="title class_">RouterModule</span>]</span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">AppRoutingModule</span> &#123; &#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// app.module.ts：告诉 Angular 如何编译和启动应用的根模块</span></span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">NgModule</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;@angular/core&#x27;</span></span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">UserModule</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;../module/user/user.module&#x27;</span>     <span class="comment">// 自定义模块</span></span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">CommonService</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;./services/common.service&#x27;</span>   <span class="comment">// 自定义服务</span></span><br><span class="line">@<span class="title class_">NgModule</span>(&#123;           <span class="comment">// 模块装饰器：接受一个元数据对象，将相关代码组织为功能单元</span></span><br><span class="line">    <span class="attr">declarations</span>: [<span class="title class_">AppComponent</span>],  <span class="comment">// 声明定义的组件、指令、管道 (静态的元数据)</span></span><br><span class="line">    <span class="attr">imports</span>: [<span class="title class_">AppRoutingModule</span>, <span class="title class_">UserModule</span>],  <span class="comment">// 导入/挂载模块：&lt;app-user&gt;  </span></span><br><span class="line">    <span class="attr">exports</span>: [<span class="title class_">FocusDirective</span>],     <span class="comment">// 导出/暴露模块</span></span><br><span class="line">    <span class="attr">providers</span>: [<span class="title class_">CommonService</span>],    <span class="comment">// 声明模块定义的公共服务 (运行时的元数据)  </span></span><br><span class="line">    <span class="attr">bootstrap</span>: [<span class="title class_">AppComponent</span>],     <span class="comment">// 指定应用的主视图</span></span><br><span class="line">    <span class="attr">entryComponents</span>: [<span class="title class_">Users</span>],      <span class="comment">// 入口文件，引导动态加载组件</span></span><br><span class="line">    <span class="attr">schemas</span>: []                    <span class="comment">// 声明非 Angular 组件、指令的元素或属性</span></span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">AppModule</span> &#123; &#125;</span><br></pre></td></tr></table></figure>



<h1 id="二、组件开发"><a href="#二、组件开发" class="headerlink" title="二、组件开发"></a>二、组件开发</h1><h2 id="组件"><a href="#组件" class="headerlink" title="组件"></a>组件</h2><blockquote>
<p>angular 应用是通过一个个组件所构成的组件树，每个组件都包含了一组独立功能并且可以重复使用，通过 angular-cli 命令行创建的组件会被放到目录 src&#x2F;app&#x2F; 并自动注册到应用的根模块 app.module.ts。</p>
</blockquote>
  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 新建一个 hero 组件</span></span><br><span class="line">ng g component hero</span><br><span class="line"></span><br><span class="line"><span class="comment">// components 目录下新建 hero 组件</span></span><br><span class="line">ng g component components/hero</span><br><span class="line"></span><br><span class="line"><span class="comment">// 组件包含的四个部分</span></span><br><span class="line">hero.<span class="property">component</span>.<span class="property">ts</span>：组件类，用来处理数据和功能，为视图呈现提供支持</span><br><span class="line">hero.<span class="property">component</span>.<span class="property">html</span>：组件对应的页面 <span class="variable constant_">HTML</span> 模板，用来呈现组件的功能</span><br><span class="line">hero.<span class="property">component</span>.<span class="property">scss</span>：只针对当前组件的样式</span><br><span class="line">hero.<span class="property">component</span>.<span class="property">spec</span>.<span class="property">ts</span>：当前组件的单元测试文件（非必须）</span><br><span class="line"></span><br><span class="line"><span class="comment">// 组件装饰器：定义组件在运行期间该如何处理、实例化和使用</span></span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">Component</span>, <span class="title class_">OnInit</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;@angular/core&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">HeroService</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;../hero.service&#x27;</span>;</span><br><span class="line">@<span class="title class_">Component</span>(&#123;</span><br><span class="line">    <span class="attr">selector</span>: <span class="string">&#x27;app-hero&#x27;</span>,  <span class="comment">// 自定义标签：标签位置会创建并插入组件实例</span></span><br><span class="line">    <span class="attr">templateUrl</span>: <span class="string">&#x27;./hero.component.html&#x27;</span>,</span><br><span class="line">    <span class="attr">styleUrls</span>: [<span class="string">&#x27;./hero.component.less&#x27;</span>],</span><br><span class="line">    <span class="attr">providers</span>: [<span class="title class_">HeroService</span>],  <span class="comment">// 声明服务</span></span><br><span class="line">    <span class="attr">template</span>:</span><br><span class="line">    <span class="string">`&lt;ul&gt;</span></span><br><span class="line"><span class="string">        &lt;li *ngFor=&quot;let hero of heroes&quot; (click)=&quot;onSelect(hero)&quot;&gt;</span></span><br><span class="line"><span class="string">    &lt;/ul&gt;`</span>,</span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">HeroComponent</span> implements <span class="title class_">OnInit</span> &#123;</span><br><span class="line">    <span class="attr">heroes</span>: <span class="title class_">Hero</span>[];</span><br><span class="line">    <span class="attr">onSelect</span>: <span class="title class_">Hero</span>;</span><br><span class="line"></span><br><span class="line">    <span class="title function_">constructor</span> (private <span class="attr">service</span>: <span class="title class_">HeroService</span>) &#123;  <span class="comment">// 注入服务</span></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">hero</span> = <span class="string">&#x27;Tony&#x27;</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    ngOnInit () &#123;     <span class="comment">// 初始化组件时调用一次的钩子</span></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">heroes</span> = <span class="variable language_">this</span>.<span class="property">service</span>.<span class="title function_">getHeroes</span>()</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    onSelect (<span class="attr">hero</span>: <span class="title class_">Hero</span>) &#123; </span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">hero</span> = hero; </span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


<h2 id="模板"><a href="#模板" class="headerlink" title="模板"></a>模板</h2>  <figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line">插值表达式</span><br><span class="line"><span class="tag">&lt;<span class="name">span</span>&gt;</span>显示变量值：&#123;&#123;name.toUpperCase()&#125;&#125;<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">span</span> <span class="attr">ngNonBindable</span>&gt;</span>显示花括号：&#123;&#123;name&#125;&#125;<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line"></span><br><span class="line">属性绑定：赋值为常量时需加引号</span><br><span class="line"><span class="tag">&lt;<span class="name">span</span> [<span class="attr">title</span>]=<span class="string">&quot;name&quot;</span>&gt;</span>推荐方式<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">a</span> <span class="attr">bind-href</span>=<span class="string">&quot;url&quot;</span>&gt;</span>bind 方式<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line"></span><br><span class="line">指令绑定</span><br><span class="line"><span class="tag">&lt;<span class="name">li</span> *<span class="attr">ngFor</span>=<span class="string">&quot;let hero of heroes; let i=index; trackBy: trackByIndex&quot;</span></span></span><br><span class="line"><span class="tag">    *<span class="attr">ngIf</span>=<span class="string">&quot;hero.name&quot;</span> </span></span><br><span class="line"><span class="tag">    [<span class="attr">ngClass</span>]=<span class="string">&quot;&#123;active: hero.isSelected&#125;&quot;</span></span></span><br><span class="line"><span class="tag">    [<span class="attr">ngStyle</span>]=<span class="string">&quot;&#123;color: hero.color&#125;&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">span</span> [<span class="attr">style.width</span>]=<span class="string">&quot;&#x27;100px&#x27;&quot;</span> [<span class="attr">class</span>]=<span class="string">&quot;&#x27;a b&#x27;&quot;</span>&gt;</span>属性绑定 []<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">span</span>&gt;</span>属性型指令：NgClass、NgStyle 设置多个动态的类名和样式<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">span</span>&gt;</span>trackByIndex(i: number, item: any): string &#123; return item.id &#125;<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line"></span><br><span class="line">事件绑定 ()</span><br><span class="line"><span class="tag">&lt;<span class="name">a</span> (<span class="attr">click</span>)=<span class="string">&quot;onClick()&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">a</span> <span class="attr">on-click</span>=<span class="string">&quot;onClick()&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line"></span><br><span class="line">双向绑定：FormModule 引入后才能使用 ngModel</span><br><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">bindon-ngModel</span>=<span class="string">&quot;hero.name&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> [(<span class="attr">ngModel</span>)]=<span class="string">&quot;hero.name&quot;</span> (<span class="attr">ngModelChange</span>)=<span class="string">&quot;onChange()&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> [<span class="attr">value</span>]=<span class="string">&quot;hero.name&quot;</span> (<span class="attr">input</span>)=<span class="string">&quot;hero.name=$event.target.value&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line">模板引用变量：可用来直接访问元素</span><br><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> #<span class="attr">refMsgInput</span> (<span class="attr">keyup</span>)=<span class="string">&quot;getRefMsg(refMsgInput.value)&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line">内嵌视图</span><br><span class="line"><span class="tag">&lt;<span class="name">template</span> [<span class="attr">ngTemplateOutlet</span>]=<span class="string">&quot;a&quot;</span> <span class="attr">ngOutletContext</span>=<span class="string">&quot;b&quot;</span>&gt;</span><span class="tag">&lt;<span class="name">template</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">&lt;!-- 精确匹配 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> [<span class="attr">ngSwitch</span>]=<span class="string">&quot;hero&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> *<span class="attr">ngSwitchCase</span>=<span class="string">&quot;&#x27;A&#x27;&quot;</span>&gt;</span>A<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> *<span class="attr">ngSwitchCase</span>=<span class="string">&quot;&#x27;B&#x27;&quot;</span>&gt;</span>B<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> *<span class="attr">ngSwitchDefault</span>&gt;</span>C<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">&lt;!-- 范围匹配 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> [<span class="attr">ngPlural</span>]=<span class="string">&quot;value&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">template</span> <span class="attr">ngPluralCase</span>=<span class="string">&quot;=0&quot;</span>&gt;</span>0<span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">template</span> <span class="attr">ngPluralCase</span>=<span class="string">&quot;=1&quot;</span>&gt;</span>1<span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">template</span> <span class="attr">ngPluralCase</span>=<span class="string">&quot;other&quot;</span>&gt;</span>其他<span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h2 id="指令"><a href="#指令" class="headerlink" title="指令"></a>指令</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 内置指令</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> 属性型指令：NgClass、NgStyle、NgModel</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> 结构型指令：NgIf、NgFor、NgSwitch</span></span><br><span class="line"><span class="comment"> **/</span> </span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 自定义指令</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> 新建指令：ng g directive directives/highlight</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> 模块声明：<span class="doctag">@NgModule</span>(&#123; declarations: [HighlightDirective] &#125;)</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> 组件使用：&lt;span [appHighlight]=&quot;green&quot;&gt;点亮&lt;/span&gt;</span></span><br><span class="line"><span class="comment"> **/</span> </span><br><span class="line">@<span class="title class_">Directive</span>(&#123; <span class="attr">selector</span>: <span class="string">&#x27;[appHighlight]&#x27;</span> &#125;)</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">HighlightDirective</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params">private el: ElementRef</span>) &#123; &#125;</span><br><span class="line"></span><br><span class="line">    @<span class="title class_">Input</span>() <span class="attr">appHighlight</span>: string;</span><br><span class="line"></span><br><span class="line">    @<span class="title class_">HostListener</span>(<span class="string">&#x27;mouseenter&#x27;</span>) <span class="title function_">onMouseEnter</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="title function_">highlight</span>(<span class="variable language_">this</span>.<span class="property">appHighlight</span> || <span class="string">&#x27;red&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    @<span class="title class_">HostListener</span>(<span class="string">&#x27;mouseleave&#x27;</span>) <span class="title function_">onMouseLeave</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="title function_">highlight</span>(<span class="literal">null</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    private <span class="title function_">highlight</span>(<span class="params">color: string</span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">el</span>.<span class="property">nativeElement</span>.<span class="property">style</span>.<span class="property">backgroundColor</span> = color;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


<h2 id="管道"><a href="#管道" class="headerlink" title="管道"></a>管道</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 内置管道：date、json、uppercase、lowercase、currency、percent、slice</span></span><br><span class="line">&lt;span&gt;&#123;&#123;today | <span class="attr">date</span>:<span class="string">&#x27;yyyy-MM-dd&#x27;</span>/<span class="string">&#x27;fullDate&#x27;</span>/<span class="string">&#x27;shortTime&#x27;</span>&#125;&#125;&lt;/span&gt;</span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">span</span>&gt;</span>&#123;&#123;&#x27;abcdefg&#x27; | slice:0:3 | uppercase&#125;&#125;<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 自定义管道</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> 新建管道：ng g pipe pipes/strLength</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> 模块声明：<span class="doctag">@NgModule</span>(&#123; declarations: [StrLengthPipe] &#125;)</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> 组件使用：&lt;span&gt;&#123;&#123;title | strLength&#125;&#125;&lt;/span&gt;</span></span><br><span class="line"><span class="comment"> **/</span></span><br><span class="line">@<span class="title class_">Pipe</span>(&#123; <span class="attr">name</span>: <span class="string">&#x27;strLength&#x27;</span> &#125;)</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">StrLengthPipe</span> implements <span class="title class_">PipeTransform</span> &#123;</span><br><span class="line">    <span class="title function_">transform</span>(<span class="attr">value</span>: string, args?: any): any &#123;</span><br><span class="line">        <span class="keyword">return</span> value.<span class="property">length</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


<h2 id="服务"><a href="#服务" class="headerlink" title="服务"></a>服务</h2><blockquote>
<p>封装了日志服务等公共方法的独立模块，通过依赖注入提供给专注业务的组件。</p>
</blockquote>
  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 自定义服务</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> 新建服务：ng g service services/hero</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> 组件使用：import 导入、providers 注册、constructor 依赖注入</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="comment">// hero.service.ts：创建可注入服务</span></span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">Injectable</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;@angular/core&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">HttpClient</span>&#125; <span class="keyword">from</span> <span class="string">&#x27;@angular/common/http&#x27;</span></span><br><span class="line">@<span class="title class_">Injectable</span>()</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">HeroService</span> &#123;</span><br><span class="line">    <span class="comment">// 依赖注入：声明一个私有属性并标记为注入点 (组件创建时赋值 Logger 单例对象)</span></span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params"></span></span><br><span class="line"><span class="params">        private logger: Logger,</span></span><br><span class="line"><span class="params">        private http: HttpClient</span>) &#123;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title function_">getHeroes</span>(): <span class="title class_">Hero</span>[] &#123;</span><br><span class="line">        <span class="keyword">let</span> heroes = []</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">http</span>.<span class="title function_">get</span>(<span class="string">&#x27;/hexo&#x27;</span>)</span><br><span class="line">        .<span class="title function_">subscribe</span>(<span class="function">(<span class="params">heroes: Hero[]</span>) =&gt;</span> &#123;</span><br><span class="line">            heroes.<span class="title function_">push</span>(...heroes);</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">logger</span>.<span class="title function_">log</span>(<span class="string">`<span class="subst">$&#123;heroes.length&#125;</span> heroes`</span>);</span><br><span class="line">        &#125;);</span><br><span class="line">        <span class="keyword">return</span> heroes;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// hero.component.ts：组件使用</span></span><br><span class="line">@<span class="title class_">Component</span>(&#123;  </span><br><span class="line">    <span class="attr">selector</span>:  <span class="string">&#x27;hero&#x27;</span>,</span><br><span class="line">    <span class="attr">templateUrl</span>: <span class="string">&#x27;./hero.component.html&#x27;</span>,</span><br><span class="line">    <span class="attr">providers</span>: [<span class="title class_">HeroService</span>]</span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">HomeComponent</span> implements <span class="title class_">OnInit</span> &#123;</span><br><span class="line">    private <span class="attr">heroes</span>: <span class="title class_">Hero</span>[] = [];</span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params">private heroService: HeroService</span>) &#123; &#125;</span><br><span class="line">    <span class="title function_">getHeroes</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">heroes</span> = <span class="variable language_">this</span>.<span class="property">heroService</span>.<span class="title function_">getHeroes</span>()</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 注册服务的三种方式</span></span><br><span class="line">@<span class="title class_">Injectable</span>()   <span class="comment">// 声明为可注入的服务但未注册</span></span><br><span class="line">@<span class="title class_">NgModule</span>(&#123;     <span class="comment">// 模块中注册：当前模块下所有组件可使用</span></span><br><span class="line">    <span class="attr">providers</span>: [<span class="title class_">HeroService</span>]</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">@<span class="title class_">Injectable</span>()</span><br><span class="line">@<span class="title class_">Component</span>(&#123;    <span class="comment">// 组件中注册：当前组件的每一个实例可使用</span></span><br><span class="line">    <span class="attr">providers</span>: [<span class="title class_">HeroService</span>]</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">@<span class="title class_">Injectable</span>(&#123;   <span class="comment">// 声明服务并在根注入器中注册，可以全局使用</span></span><br><span class="line">    <span class="attr">providedIn</span>: <span class="string">&#x27;root&#x27;</span>  </span><br><span class="line">&#125;) </span><br></pre></td></tr></table></figure>


<h2 id="生命周期"><a href="#生命周期" class="headerlink" title="生命周期"></a>生命周期</h2><blockquote>
<p>组件加载过程中会按照以下顺序依次执行，页面加载过程中涉及数据绑定和更新时会再次触发 ngDoCheck、ngAfterContentChecked、ngAfterViewChecked。</p>
</blockquote>
<ul>
<li><strong>constructor</strong>：构造函数而并非生命周期钩子，一般用于注入服务。</li>
<li><strong>ngOnChanges</strong>：绑定数据变化时调用，注意无法监听对象内部数据的变化。</li>
<li><strong>ngOnInit</strong>：组件初始化，在首次 ngOnChanges 之后调用。</li>
<li><strong>ngDoCheck</strong>：可以检测一切数据的变化，可用来自定义检测逻辑。</li>
<li><strong>ngAfterContentInit</strong>：组件内容初始化之后。</li>
<li><strong>ngAfterContentChecked</strong>：组件内容变更之后。</li>
<li><strong>ngAfterViewInit</strong>：视图初始化之后。</li>
<li><strong>ngAfterViewChecked</strong>：视图每次发生变化时。</li>
<li><strong>ngOnDestroy</strong>：组件注销时调用一次。</li>
</ul>
<h2 id="组件通信"><a href="#组件通信" class="headerlink" title="组件通信"></a>组件通信</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// ============================= 父子通信 ===============================</span></span><br><span class="line"><span class="comment">// 父组件</span></span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">Component</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;@angular/core&#x27;</span>;</span><br><span class="line">@<span class="title class_">Component</span>(&#123;</span><br><span class="line">    <span class="attr">selector</span>: <span class="string">&#x27;app-parent&#x27;</span>,</span><br><span class="line">    <span class="attr">template</span>: <span class="string">`</span></span><br><span class="line"><span class="string">    &lt;button (click)=&quot;printData()&quot;&gt;调用子组件的方法&lt;/button&gt;</span></span><br><span class="line"><span class="string">    &lt;app-child #child [name]=&quot;name&quot; (childEmit)=&quot;onClick($event)&quot;&gt;&lt;/app-child&gt;</span></span><br><span class="line"><span class="string">    `</span></span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">ParentComponent</span> &#123;</span><br><span class="line">    <span class="comment">// 1、父组件发送数据</span></span><br><span class="line">    public <span class="attr">name</span>:string = <span class="string">&#x27;儿子&#x27;</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 2、父组件接收数据</span></span><br><span class="line">    public <span class="title function_">onClick</span>(<span class="attr">bool</span>:<span class="title class_">Boolean</span>):<span class="keyword">void</span>&#123; &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 3、父组件获取子组件的实例：static 是否在运行更改检测前处理查询结果</span></span><br><span class="line">    @<span class="title class_">ViewChild</span>(<span class="string">&#x27;child&#x27;</span>, &#123; <span class="attr">static</span>: <span class="literal">true</span> &#125;)</span><br><span class="line">    public child!: <span class="title class_">ElementRef</span>&lt;<span class="title class_">HTMLElement</span>&gt;;</span><br><span class="line"></span><br><span class="line">    public <span class="title function_">printData</span>():<span class="keyword">void</span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">child</span>)  &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">child</span>.<span class="title function_">print</span>(<span class="string">&#x27;hello2&#x27;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 子组件</span></span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">Component</span>, <span class="title class_">Input</span>, <span class="title class_">Output</span>, <span class="title class_">EventEmitter</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;@angular/core&#x27;</span>;</span><br><span class="line">@<span class="title class_">Component</span>(&#123;</span><br><span class="line">    <span class="attr">selector</span>: <span class="string">&#x27;app-child&#x27;</span>,</span><br><span class="line">    <span class="attr">template</span>: <span class="string">`&lt;h3 (click)=&quot;myClick()&quot;&gt;&#123;&#123;name&#125;&#125;&lt;/h3&gt;`</span></span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">HeroChildComponent</span> &#123;</span><br><span class="line">    <span class="comment">// 1、子组件接收数据</span></span><br><span class="line">    @<span class="title class_">Input</span>() </span><br><span class="line">    public <span class="attr">name</span>: string;  </span><br><span class="line"></span><br><span class="line">    <span class="comment">// 2、子组件发送数据</span></span><br><span class="line">    @<span class="title class_">Output</span>()</span><br><span class="line">    public readonly <span class="attr">childEmit</span>: <span class="title class_">EventEmitter</span>&lt;boolean&gt; = <span class="keyword">new</span> <span class="title class_">EventEmitter</span>();</span><br><span class="line"></span><br><span class="line">    public <span class="title function_">myClick</span>():<span class="keyword">void</span>&#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">childEmit</span>.<span class="title function_">emit</span>(<span class="literal">true</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public <span class="title function_">print</span>(<span class="attr">content</span>:string):<span class="keyword">void</span>&#123; &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// ========================= 全局通信 ============================</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> dataService.ts</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> BehaviorSubject：用来创建一个共享服务，实现发布订阅模式</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> rxjs：使用 Observables 的响应式编程的库，方便编写异步或回调代码</span></span><br><span class="line"><span class="comment"> **/</span> </span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">Injectable</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;@angular/core&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">BehaviorSubject</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;rxjs/BehaviorSubject&#x27;</span>;</span><br><span class="line"></span><br><span class="line">@<span class="title class_">Injectable</span>(&#123; <span class="attr">providedIn</span>: <span class="string">&#x27;root&#x27;</span> &#125;)</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">MessageService</span> &#123;</span><br><span class="line">    private message = <span class="keyword">new</span> <span class="title class_">BehaviorSubject</span>&lt;string&gt;(<span class="string">&#x27;start&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    public <span class="title function_">getMessage</span>(): <span class="title class_">Observable</span>&lt;string&gt; &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">message</span>.<span class="title function_">asObservable</span>();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public <span class="title function_">setMessage</span>(<span class="attr">msg</span>: string): <span class="keyword">void</span> &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">message</span>.<span class="title function_">next</span>(msg);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// a.component.ts：发布</span></span><br><span class="line"><span class="variable language_">this</span>.<span class="property">messageService</span>.<span class="title function_">setMessage</span>(<span class="string">&#x27;update&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// b.component.ts：订阅、取消订阅</span></span><br><span class="line"><span class="title function_">ngOnInit</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">messageService</span>.<span class="title function_">getMessage</span>().<span class="title function_">subscribe</span>(<span class="function"><span class="params">m</span> =&gt;</span> &#123; &#125;)</span><br><span class="line">&#125;</span><br><span class="line"><span class="title function_">ngOnDestroy</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">isRecoverSub</span>.<span class="title function_">unsubscribe</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


<h1 id="三、表单控件"><a href="#三、表单控件" class="headerlink" title="三、表单控件"></a>三、表单控件</h1><blockquote>
<p>模板驱动表单通过表单指令将数据和相关验证绑定到组件模板并通过修改 ngModel 绑定的数据模型来完成数据更新，响应式表单则是在表单数据发生变更时通过 FormControl 实例返回一个新的数据模型而不是直接修改原模型。</p>
</blockquote>
<h2 id="模板驱动表单"><a href="#模板驱动表单" class="headerlink" title="模板驱动表单"></a>模板驱动表单</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// app.module.js：引入 ngModel 依赖的 FormsModule</span></span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">FormsModule</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;@angular/forms&#x27;</span>;</span><br><span class="line">@<span class="title class_">NgModule</span>(&#123;</span><br><span class="line">    <span class="attr">imports</span>: [<span class="title class_">FormsModule</span>],</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// css 样式：输入内容不满足条件时进行提示</span></span><br><span class="line">.<span class="property">ng</span>-valid[required], .<span class="property">ng</span>-valid.<span class="property">required</span>  &#123;</span><br><span class="line">    border-<span class="attr">left</span>: 5px solid #42A948;</span><br><span class="line">&#125;</span><br><span class="line">.<span class="property">ng</span>-<span class="attr">invalid</span>:<span class="title function_">not</span>(<span class="params">form</span>)  &#123;</span><br><span class="line">    border-<span class="attr">left</span>: 5px solid #a94442;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 常用的控件状态</span></span><br><span class="line">valid、invalid：校验成功/失败</span><br><span class="line">pristine、dirty：数据未/已被修改</span><br><span class="line">enabled、disabled：启用/禁用状态</span><br><span class="line">touched、untouched：未/已被触摸或点击过</span><br></pre></td></tr></table></figure>

  <figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">form</span> (<span class="attr">ngSubmit</span>)=<span class="string">&quot;submit()&quot;</span> #<span class="attr">heroForm</span>=<span class="string">&quot;ngForm&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;form-group&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">label</span> <span class="attr">for</span>=<span class="string">&quot;name&quot;</span>&gt;</span>姓名：<span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- 将 ngModel 指令通过模板引用变量的形式暴露出来，从而获取控件状态 --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">name</span>=<span class="string">&quot;name&quot;</span> <span class="attr">id</span>=<span class="string">&quot;name&quot;</span> [(<span class="attr">ngModel</span>)]=<span class="string">&quot;hero.name&quot;</span> </span></span><br><span class="line"><span class="tag">               <span class="attr">autocomplete</span>=<span class="string">&quot;off&quot;</span> <span class="attr">required</span> <span class="attr">minlength</span>=<span class="string">&quot;4&quot;</span> #<span class="attr">name</span>=<span class="string">&quot;ngModel&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">div</span> *<span class="attr">ngIf</span>=<span class="string">&quot;name.invalid &amp;&amp; (name.dirty || name.touched)&quot;</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">div</span> *<span class="attr">ngIf</span>=<span class="string">&quot;name.errors.required&quot;</span>&gt;</span>姓名不能为空<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">div</span> *<span class="attr">ngIf</span>=<span class="string">&quot;name.errors.minlength&quot;</span>&gt;</span>姓名信息至少 4 个字符长度<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;form-group&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">label</span> <span class="attr">for</span>=<span class="string">&quot;age&quot;</span>&gt;</span>年龄：<span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;number&quot;</span> <span class="attr">name</span>=<span class="string">&quot;age&quot;</span> <span class="attr">id</span>=<span class="string">&quot;age&quot;</span> [(<span class="attr">ngModel</span>)]=<span class="string">&quot;hero.age&quot;</span> </span></span><br><span class="line"><span class="tag">               <span class="attr">class</span>=<span class="string">&quot;form-control&quot;</span> <span class="attr">required</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;form-group&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">label</span> <span class="attr">for</span>=<span class="string">&quot;gender&quot;</span>&gt;</span>性别：<span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">div</span> *<span class="attr">ngFor</span>=<span class="string">&quot;let gender of genderList&quot;</span> <span class="attr">class</span>=<span class="string">&quot;form-check&quot;</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;radio&quot;</span> <span class="attr">name</span>=<span class="string">&quot;gender&quot;</span> <span class="attr">id</span>=<span class="string">&quot;&#123;&#123;gender.id&#125;&#125;&quot;</span> </span></span><br><span class="line"><span class="tag">                   <span class="attr">value</span>=<span class="string">&quot;&#123;&#123;gender.value&#125;&#125;&quot;</span> [(<span class="attr">ngModel</span>)]=<span class="string">&quot;hero.gender&quot;</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">label</span> <span class="attr">for</span>=<span class="string">&quot;&#123;&#123;gender.id&#125;&#125;&quot;</span>&gt;</span>&#123;&#123;gender.text&#125;&#125;<span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;form-group&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">label</span> <span class="attr">for</span>=<span class="string">&quot;address&quot;</span>&gt;</span>住址：<span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">select</span> <span class="attr">name</span>=<span class="string">&quot;address&quot;</span> <span class="attr">id</span>=<span class="string">&quot;address&quot;</span> [(<span class="attr">ngModel</span>)]=<span class="string">&quot;hero.address&quot;</span> </span></span><br><span class="line"><span class="tag">                <span class="attr">class</span>=<span class="string">&quot;form-control&quot;</span> <span class="attr">required</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">option</span> <span class="attr">value</span>=<span class="string">&quot;&#123;&#123;address&#125;&#125;&quot;</span> *<span class="attr">ngFor</span>=<span class="string">&quot;let address of addressList&quot;</span></span></span><br><span class="line"><span class="tag">            &gt;</span>&#123;&#123;address&#125;&#125;<span class="tag">&lt;/<span class="name">option</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">select</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">button</span> <span class="attr">type</span>=<span class="string">&quot;submit&quot;</span> [<span class="attr">disabled</span>]=<span class="string">&quot;!heroForm.form.valid&quot;</span>&gt;</span>Submit<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span>&gt;</span>表单数据：&#123;&#123;hero | json&#125;&#125;<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h2 id="响应式表单"><a href="#响应式表单" class="headerlink" title="响应式表单"></a>响应式表单</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// app.module.js：引入 FormControl 依赖的 ReactiveFormsModule</span></span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">ReactiveFormsModule</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;@angular/forms&#x27;</span>;</span><br><span class="line">@<span class="title class_">NgModule</span>(&#123;</span><br><span class="line">    <span class="attr">imports</span>: [<span class="title class_">ReactiveFormsModule</span>],</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 表单：&lt;input type=&quot;text&quot; id=&quot;name&quot; [formControl]=&#x27;name&#x27; autocomplete=&quot;off&quot;&gt;</span></span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">FormControl</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;@angular/forms&#x27;</span>;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">ReactiveFormsComponent</span> implements <span class="title class_">OnInit</span> &#123;</span><br><span class="line">    <span class="comment">// 定义属性来承接 FormControl 实例</span></span><br><span class="line">    public name = <span class="keyword">new</span> <span class="title class_">FormControl</span>(<span class="string">&#x27;1&#x27;</span>);</span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params"></span>) &#123; &#125;</span><br><span class="line">    <span class="title function_">getName</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">name</span>.<span class="property">value</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title function_">setName</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">name</span>.<span class="title function_">setValue</span>(<span class="number">2</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 复杂表单</span></span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">Validators</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;@angular/forms&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">FormBuilder</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;@angular/forms&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">FormControl</span>, <span class="title class_">FormGroup</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;@angular/forms&#x27;</span>;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">ReactiveFormsComponent</span> implements <span class="title class_">OnInit</span> &#123;</span><br><span class="line">    <span class="comment">// 定义对象属性来承接 FormGroup 实例</span></span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params"></span>) &#123; &#125;</span><br><span class="line">    public profileForm = <span class="keyword">new</span> <span class="title class_">FormGroup</span>(&#123;</span><br><span class="line">        <span class="attr">name</span>: <span class="keyword">new</span> <span class="title class_">FormControl</span>(<span class="string">&#x27;李先生&#x27;</span>),</span><br><span class="line">        <span class="attr">age</span>: <span class="keyword">new</span> <span class="title class_">FormControl</span>(<span class="number">12</span>),</span><br><span class="line">        <span class="attr">address</span>: <span class="keyword">new</span> <span class="title class_">FormGroup</span>(&#123;</span><br><span class="line">            <span class="attr">province</span>: <span class="keyword">new</span> <span class="title class_">FormControl</span>(<span class="string">&#x27;河南省&#x27;</span>),</span><br><span class="line">            <span class="attr">city</span>: <span class="keyword">new</span> <span class="title class_">FormControl</span>(<span class="string">&#x27;郑州市&#x27;</span>)</span><br><span class="line">        &#125;)</span><br><span class="line">    &#125;)</span><br><span class="line">    <span class="comment">// 表单控件过多时 FormGroup 很麻烦，此时可使用 FormBuilder 表单构造器 </span></span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params">private formBuilder: FormBuilder</span>) &#123; &#125;</span><br><span class="line">    public profileForm = <span class="variable language_">this</span>.<span class="property">formBuilder</span>.<span class="title function_">group</span>(&#123;</span><br><span class="line">        <span class="attr">name</span>: [<span class="string">&#x27;&#x27;</span>, [</span><br><span class="line">            <span class="title class_">Validators</span>.<span class="property">required</span>,</span><br><span class="line">            <span class="title class_">Validators</span>.<span class="title function_">minLength</span>(<span class="number">4</span>)</span><br><span class="line">        ]],</span><br><span class="line">        <span class="attr">age</span>: [<span class="number">12</span>],</span><br><span class="line">        <span class="attr">address</span>: <span class="variable language_">this</span>.<span class="property">formBuilder</span>.<span class="title function_">group</span>(&#123;</span><br><span class="line">            <span class="attr">province</span>: [<span class="string">&#x27;河南省&#x27;</span>],</span><br><span class="line">            <span class="attr">city</span>: [<span class="string">&#x27;郑州市&#x27;</span>],</span><br><span class="line">            <span class="attr">district</span>: [<span class="string">&#x27;金水区&#x27;</span>]</span><br><span class="line">        &#125;)</span><br><span class="line">    &#125;)</span><br><span class="line">    <span class="comment">// 验证控件添加 getter 方法用来在模板中获取状态信息</span></span><br><span class="line">    <span class="keyword">get</span> <span class="title function_">name</span>() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">profileForm</span>.<span class="title function_">get</span>(<span class="string">&#x27;name&#x27;</span>)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="title function_">updateProfile</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="comment">// 更新某个控件的数据</span></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">profileForm</span>.<span class="title function_">patchValue</span>(&#123; <span class="attr">name</span>: <span class="string">&#x27;123&#x27;</span> &#125;)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title function_">submit</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">profileForm</span>.<span class="property">value</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
  <figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">form</span> [<span class="attr">formGroup</span>]=<span class="string">&#x27;profileForm&#x27;</span> (<span class="attr">ngSubmit</span>)=<span class="string">&#x27;submit()&#x27;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;form-group&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">label</span> <span class="attr">for</span>=<span class="string">&quot;name&quot;</span>&gt;</span>姓名：<span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">id</span>=<span class="string">&quot;name&quot;</span> <span class="attr">formControlName</span>=<span class="string">&#x27;name&#x27;</span> <span class="attr">autocomplete</span>=<span class="string">&quot;off&quot;</span></span></span><br><span class="line"><span class="tag">               <span class="attr">class</span>=<span class="string">&quot;form-control&quot;</span> <span class="attr">required</span> <span class="attr">minlength</span>=<span class="string">&quot;4&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">div</span> *<span class="attr">ngIf</span>=<span class="string">&quot;name.invalid &amp;&amp; (name.dirty || name.touched)&quot;</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">div</span> *<span class="attr">ngIf</span>=<span class="string">&quot;name.errors.required&quot;</span>&gt;</span>姓名不能为空<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">div</span> *<span class="attr">ngIf</span>=<span class="string">&quot;name.errors.minlength&quot;</span>&gt;</span>姓名信息至少 4 个字符长度<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;form-group&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">label</span> <span class="attr">for</span>=<span class="string">&quot;age&quot;</span>&gt;</span>年龄：<span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;number&quot;</span> <span class="attr">id</span>=<span class="string">&quot;age&quot;</span> <span class="attr">formControlName</span>=<span class="string">&#x27;age&#x27;</span> <span class="attr">autocomplete</span>=<span class="string">&quot;off&quot;</span></span></span><br><span class="line"><span class="tag">               <span class="attr">class</span>=<span class="string">&quot;form-control&quot;</span> <span class="attr">required</span> <span class="attr">step</span>=<span class="string">&quot;1&quot;</span> <span class="attr">max</span>=<span class="string">&quot;100&quot;</span> <span class="attr">min</span>=<span class="string">&quot;1&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">formGroupName</span>=<span class="string">&#x27;address&#x27;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;form-group&quot;</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">label</span> <span class="attr">for</span>=<span class="string">&quot;province&quot;</span>&gt;</span>省：<span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">id</span>=<span class="string">&quot;province&quot;</span> <span class="attr">formControlName</span>=<span class="string">&#x27;province&#x27;</span></span></span><br><span class="line"><span class="tag">                   <span class="attr">class</span>=<span class="string">&quot;form-control&quot;</span> <span class="attr">autocomplete</span>=<span class="string">&quot;off&quot;</span> <span class="attr">required</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;form-group&quot;</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;<span class="name">label</span> <span class="attr">for</span>=<span class="string">&quot;city&quot;</span>&gt;</span>市：<span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">id</span>=<span class="string">&quot;city&quot;</span> <span class="attr">formControlName</span>=<span class="string">&#x27;city&#x27;</span> </span></span><br><span class="line"><span class="tag">                 <span class="attr">class</span>=<span class="string">&quot;form-control&quot;</span> <span class="attr">autocomplete</span>=<span class="string">&quot;off&quot;</span> <span class="attr">required</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">button</span> <span class="attr">type</span>=<span class="string">&quot;button&quot;</span> (<span class="attr">click</span>)=<span class="string">&quot;updateProfile()&quot;</span>&gt;</span>更新<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">button</span> <span class="attr">type</span>=<span class="string">&quot;submit&quot;</span> [<span class="attr">disabled</span>]=<span class="string">&quot;!profileForm.valid&quot;</span>&gt;</span>提交<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span>&gt;</span>FormGroup 表单组控件的值： &#123;&#123;profileForm.value | json&#125;&#125;<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h2 id="自定义验证"><a href="#自定义验证" class="headerlink" title="自定义验证"></a>自定义验证</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 响应式表单自定义验证器：&lt;div *ngIf=&quot;name.errors.nameinvalid&quot;&gt;姓名无效&lt;/div&gt;</span></span><br><span class="line">public profileForm = <span class="variable language_">this</span>.<span class="property">formBuilder</span>.<span class="title function_">group</span>(&#123;</span><br><span class="line">    <span class="attr">name</span>: [<span class="string">&#x27;&#x27;</span>, [</span><br><span class="line">        <span class="title class_">Validators</span>.<span class="property">required</span>,</span><br><span class="line">        <span class="title class_">Validators</span>.<span class="title function_">minLength</span>(<span class="number">4</span>),</span><br><span class="line">        validatorName</span><br><span class="line">    ]]</span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">validatorName</span>(<span class="params">name: FormControl</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> name.<span class="property">value</span> === <span class="string">&#x27;lala&#x27;</span> ? &#123; <span class="attr">nameinvalid</span>: <span class="literal">true</span> &#125; : <span class="literal">null</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 模板驱动表单添加一个自定义指令实现校验：&lt;input type=&quot;text&quot; appHeroValidate&gt;</span></span><br><span class="line">ng g directive direactives/hero-validate</span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">Directive</span>, <span class="title class_">Input</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;@angular/core&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">AbstractControl</span>, <span class="title class_">Validator</span>, <span class="title class_">ValidationErrors</span>, <span class="variable constant_">NG_VALIDATORS</span> &#125; </span><br><span class="line"><span class="keyword">from</span> <span class="string">&#x27;@angular/forms&#x27;</span>;</span><br><span class="line"></span><br><span class="line">@<span class="title class_">Directive</span>(&#123;</span><br><span class="line">    <span class="attr">selector</span>: <span class="string">&#x27;[appHeroValidate]&#x27;</span>,</span><br><span class="line">    <span class="attr">providers</span>: [&#123; </span><br><span class="line">        <span class="attr">provide</span>: <span class="variable constant_">NG_VALIDATORS</span>, </span><br><span class="line">        <span class="attr">useExisting</span>: <span class="title class_">HeroValidateDirective</span>, </span><br><span class="line">        <span class="attr">multi</span>: <span class="literal">true</span>  <span class="comment">// 将该验证器添加到现存的验证器集合</span></span><br><span class="line">    &#125;]</span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">HeroValidateDirective</span> implements <span class="title class_">Validator</span> &#123;</span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params"></span>) &#123; &#125;</span><br><span class="line">    <span class="comment">// 对指定的控件执行同步验证方法</span></span><br><span class="line">    <span class="title function_">validate</span>(<span class="attr">control</span>: <span class="title class_">AbstractControl</span>): <span class="title class_">ValidationErrors</span> | <span class="literal">null</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> control.<span class="property">value</span> === <span class="string">&#x27;lala&#x27;</span> ? &#123; <span class="string">&#x27;nameInvalid&#x27;</span>: <span class="literal">true</span> &#125; : <span class="literal">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="跨字段验证"><a href="#跨字段验证" class="headerlink" title="跨字段验证"></a>跨字段验证</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 响应式表单：&lt;div *ngIf=&quot;profileForm.errors?.formInvalid&gt;l 不是 12 岁&lt;/div&gt;</span></span><br><span class="line"><span class="keyword">import</span> &#123; </span><br><span class="line">    <span class="title class_">Validators</span>,</span><br><span class="line">    <span class="title class_">FormBuilder</span>,</span><br><span class="line">    <span class="title class_">FormControl</span>, </span><br><span class="line">    <span class="title class_">FormGroup</span>, </span><br><span class="line">    <span class="title class_">ValidatorFn</span>, </span><br><span class="line">    <span class="title class_">ValidationErrors</span> </span><br><span class="line">&#125; <span class="keyword">from</span> <span class="string">&#x27;@angular/forms&#x27;</span>;</span><br><span class="line"><span class="keyword">const</span> <span class="attr">formCrossValidator</span>: <span class="title class_">ValidatorFn</span> = (<span class="attr">controlGroup</span>: <span class="title class_">FormGroup</span>): </span><br><span class="line"><span class="title class_">ValidationErrors</span> | <span class="function"><span class="params">null</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="comment">// 获取子控件的信息</span></span><br><span class="line">    <span class="keyword">const</span> name = controlGroup.<span class="title function_">get</span>(<span class="string">&#x27;name&#x27;</span>);</span><br><span class="line">    <span class="keyword">const</span> age = controlGroup.<span class="title function_">get</span>(<span class="string">&#x27;age&#x27;</span>);</span><br><span class="line">    <span class="keyword">const</span> flag = name &amp;&amp; age &amp;&amp; name.<span class="property">value</span> === <span class="string">&#x27;l&#x27;</span> &amp;&amp; age.<span class="property">value</span> === <span class="number">12</span>;</span><br><span class="line">    <span class="keyword">return</span> flag ? &#123; <span class="string">&#x27;formInvalid&#x27;</span>: <span class="literal">true</span> &#125; : <span class="literal">null</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">ReactiveFormsComponent</span> implements <span class="title class_">OnInit</span> &#123;</span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params">private formBuilder: FormBuilder</span>) &#123; &#125;</span><br><span class="line">    public profileForm = <span class="variable language_">this</span>.<span class="property">formBuilder</span>.<span class="title function_">group</span>(&#123;</span><br><span class="line">      <span class="attr">name</span>: [<span class="string">&#x27;&#x27;</span>, [</span><br><span class="line">          <span class="title class_">Validators</span>.<span class="property">required</span>,</span><br><span class="line">          <span class="title class_">Validators</span>.<span class="title function_">minLength</span>(<span class="number">4</span>)</span><br><span class="line">      ]],</span><br><span class="line">      <span class="attr">age</span>: [<span class="number">12</span>],</span><br><span class="line">      <span class="attr">address</span>: <span class="variable language_">this</span>.<span class="property">formBuilder</span>.<span class="title function_">group</span>(&#123; <span class="attr">province</span>: [<span class="string">&#x27;河南省&#x27;</span>], <span class="attr">city</span>: [<span class="string">&#x27;郑州市&#x27;</span>] &#125;)</span><br><span class="line">    &#125;, &#123; <span class="attr">validators</span>: [formCrossValidator] &#125;);     <span class="comment">// 添加针对控件组的验证器</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 模板驱动表单：自定义指令</span></span><br><span class="line"><span class="keyword">import</span> &#123; </span><br><span class="line">    <span class="title class_">Validator</span>, </span><br><span class="line">    <span class="title class_">AbstractControl</span>, </span><br><span class="line">    <span class="title class_">ValidationErrors</span>, </span><br><span class="line">    <span class="title class_">ValidatorFn</span>, </span><br><span class="line">    <span class="title class_">FormGroup</span>, </span><br><span class="line">    <span class="variable constant_">NG_VALIDATORS</span> </span><br><span class="line">&#125; <span class="keyword">from</span> <span class="string">&#x27;@angular/forms&#x27;</span>;</span><br><span class="line"><span class="keyword">const</span> <span class="attr">formCrossValidator</span>: <span class="title class_">ValidatorFn</span> = (<span class="attr">controlGroup</span>: <span class="title class_">FormGroup</span>): </span><br><span class="line"><span class="title class_">ValidationErrors</span> | <span class="function"><span class="params">null</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> name = controlGroup.<span class="title function_">get</span>(<span class="string">&#x27;name&#x27;</span>);</span><br><span class="line">    <span class="keyword">const</span> age = controlGroup.<span class="title function_">get</span>(<span class="string">&#x27;age&#x27;</span>);</span><br><span class="line">    <span class="keyword">const</span> flag = name &amp;&amp; age &amp;&amp; name.<span class="property">value</span> === <span class="string">&#x27;l&#x27;</span> &amp;&amp; age.<span class="property">value</span> === <span class="number">12</span>;</span><br><span class="line">    <span class="keyword">return</span> flag ? &#123; <span class="string">&#x27;formInvalid&#x27;</span>: <span class="literal">true</span> &#125; : <span class="literal">null</span>;</span><br><span class="line">&#125;;</span><br><span class="line">@<span class="title class_">Directive</span>(&#123;</span><br><span class="line">    <span class="attr">selector</span>: <span class="string">&#x27;[appCrossFieldValidate]&#x27;</span>,</span><br><span class="line">    <span class="attr">providers</span>: [&#123; </span><br><span class="line">        <span class="attr">provide</span>: <span class="variable constant_">NG_VALIDATORS</span>, </span><br><span class="line">        <span class="attr">useExisting</span>: <span class="title class_">CrossFieldValidateDirective</span>, </span><br><span class="line">        <span class="attr">multi</span>: <span class="literal">true</span> </span><br><span class="line">    &#125;]</span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">CrossFieldValidateDirective</span> implements <span class="title class_">Validator</span> &#123;</span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params"></span>) &#123; &#125;</span><br><span class="line">    <span class="title function_">validate</span>(<span class="attr">control</span>: <span class="title class_">AbstractControl</span>): <span class="title class_">ValidationErrors</span> | <span class="literal">null</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">formCrossValidator</span>(control)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>





<h1 id="四、HTTP-请求"><a href="#四、HTTP-请求" class="headerlink" title="四、HTTP 请求"></a>四、HTTP 请求</h1><h2 id="http-服务"><a href="#http-服务" class="headerlink" title="http 服务"></a>http 服务</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// app.module.ts：请求模块、解决跨域模块</span></span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">HttpClientModule</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;@angular/common/http&#x27;</span>;</span><br><span class="line">@<span class="title class_">NgModule</span>(&#123; <span class="attr">imports</span>: [<span class="title class_">HttpClientModule</span>] &#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// src/proxy.conf.json：解决本地开发跨域问题</span></span><br><span class="line"><span class="string">&quot;/api&quot;</span>: &#123;</span><br><span class="line">    <span class="string">&quot;target&quot;</span>: <span class="string">&quot;http://localhost:3000&quot;</span>,</span><br><span class="line">    <span class="string">&quot;secure&quot;</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="string">&quot;pathRewrite&quot;</span>: &#123; <span class="string">&quot;^/api&quot;</span>: <span class="string">&quot;&quot;</span> &#125;,</span><br><span class="line">    <span class="string">&quot;changeOrigin&quot;</span>: <span class="literal">true</span>    <span class="comment">// 后端服务器不在 localhost 时设置</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="string">&quot;serve&quot;</span>: &#123;     <span class="comment">// angular.json 添加 proxyConfig 选项</span></span><br><span class="line">    <span class="string">&quot;builder&quot;</span>: <span class="string">&quot;@angular-devkit/build-angular:dev-server&quot;</span>,</span><br><span class="line">    <span class="string">&quot;options&quot;</span>: &#123;</span><br><span class="line">        <span class="string">&quot;browserTarget&quot;</span>: <span class="string">&quot;hero:build&quot;</span>,</span><br><span class="line">        <span class="string">&quot;proxyConfig&quot;</span>: <span class="string">&quot;src/proxy.conf.json&quot;</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 应用环境配置：如果线上环境不需要路径 /api</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> environment = &#123;      <span class="comment">// environment.ts</span></span><br><span class="line">    <span class="attr">production</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">baseUrl</span>: <span class="string">&#x27;/api&#x27;</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> environment = &#123;      <span class="comment">// environment.prod.ts</span></span><br><span class="line">    <span class="attr">production</span>: <span class="literal">true</span>,</span><br><span class="line">    <span class="attr">baseUrl</span>: <span class="string">&#x27;&#x27;</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// hero.service.ts：封装请求服务</span></span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">Injectable</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;@angular/core&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">Observable</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;rxjs&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; map, catchError &#125; <span class="keyword">from</span> <span class="string">&#x27;rxjs/operators&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; forkJoin &#125; <span class="keyword">from</span> <span class="string">&quot;rxjs/observable/forkJoin&quot;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">HttpClient</span>, <span class="title class_">HttpHeaders</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;@angular/common/http&#x27;</span></span><br><span class="line"><span class="keyword">import</span> &#123; environment &#125; <span class="keyword">from</span> <span class="string">&#x27;../environments/environment&#x27;</span>;</span><br><span class="line"></span><br><span class="line">@<span class="title class_">Injectable</span>(&#123; <span class="attr">providedIn</span>: <span class="string">&#x27;root&#x27;</span> &#125;)</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">HeroService</span> &#123;</span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params">private http: HttpClient</span>) &#123; &#125;</span><br><span class="line">    private <span class="attr">baseUrl</span>: string = environment.<span class="property">baseUrl</span>;</span><br><span class="line"></span><br><span class="line">    <span class="title function_">getHeroes</span>(params): <span class="title class_">Hero</span>[] &#123;</span><br><span class="line">        <span class="keyword">let</span> heroes = []</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">http</span>.<span class="title function_">get</span>(<span class="string">&#x27;/hexo&#x27;</span>, &#123;<span class="attr">params</span>: params&#125;)</span><br><span class="line">        .<span class="title function_">subscribe</span>(<span class="function">(<span class="params">heroes: Hero[]</span>) =&gt;</span> &#123;</span><br><span class="line">            heroes.<span class="title function_">push</span>(...heroes)</span><br><span class="line">        &#125;, <span class="function"><span class="params">error</span> =&gt;</span> &#123;</span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">error</span>(error);</span><br><span class="line">        &#125;)</span><br><span class="line">        <span class="keyword">return</span> heroes</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="title function_">ngOnInit</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">let</span> characterUrl = <span class="variable language_">this</span>.<span class="property">http</span>.<span class="title function_">get</span>(<span class="string">&#x27;/api/people&#x27;</span>);</span><br><span class="line">        <span class="keyword">let</span> homeworldUrl = <span class="variable language_">this</span>.<span class="property">http</span>.<span class="title function_">get</span>(<span class="string">&#x27;/api/planet&#x27;</span>);</span><br><span class="line">        <span class="comment">// 处理并发请求：forkJoin 相当于 Promise.all()</span></span><br><span class="line">        <span class="title function_">forkJoin</span>([characterUrl, homeworldUrl])</span><br><span class="line">        .<span class="title function_">subscribe</span>(<span class="function"><span class="params">results</span> =&gt;</span> &#123;</span><br><span class="line">            <span class="keyword">let</span> character = results[<span class="number">0</span>];</span><br><span class="line">            <span class="keyword">let</span> homeworld = results[<span class="number">1</span>];</span><br><span class="line">        &#125;)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// jsonp 解决跨域：第二个参数必须和后端对应上</span></span><br><span class="line">    getDataJsonp (url) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">http</span>.<span class="title function_">jsonp</span>(url, <span class="string">&#x27;callback&#x27;</span>)</span><br><span class="line">        .<span class="title function_">subscribe</span>(<span class="function"><span class="params">res</span> =&gt;</span> &#123;</span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">log</span>(res)</span><br><span class="line">        &#125;)  </span><br><span class="line">    &#125;</span><br><span class="line">  </span><br><span class="line">    public get (<span class="attr">url</span>: string) &#123;</span><br><span class="line">        <span class="keyword">let</span> options = &#123;</span><br><span class="line">            <span class="attr">params</span>: params,</span><br><span class="line">            <span class="attr">headers</span>: <span class="keyword">new</span> <span class="title class_">Headers</span>(&#123; <span class="string">&#x27;token&#x27;</span>: <span class="string">&#x27;abcdefgh&#x27;</span> &#125;)</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">http</span>.<span class="title function_">get</span>(<span class="string">`<span class="subst">$&#123;<span class="variable language_">this</span>.baseUrl&#125;</span><span class="subst">$&#123;url&#125;</span>`</span>, options)</span><br><span class="line">            .<span class="title function_">pipe</span>(<span class="title function_">map</span>(<span class="variable language_">this</span>.<span class="property">extractData</span>), <span class="title function_">catchError</span>(<span class="variable language_">this</span>.<span class="property">handleError</span>));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public <span class="title function_">post</span>(<span class="params">url: string, data?: any</span>) &#123;</span><br><span class="line">        <span class="keyword">let</span> options = &#123;</span><br><span class="line">            <span class="attr">headers</span>: <span class="keyword">new</span> <span class="title class_">Headers</span>(&#123; <span class="string">&#x27;Content-Type&#x27;</span>: <span class="string">&#x27;application/json&#x27;</span> &#125;)</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">http</span>.<span class="title function_">post</span>(<span class="string">`<span class="subst">$&#123;<span class="variable language_">this</span>.baseUrl&#125;</span><span class="subst">$&#123;url&#125;</span>`</span>, data, options)</span><br><span class="line">            .<span class="title function_">pipe</span>(<span class="title function_">map</span>(<span class="variable language_">this</span>.<span class="property">extractData</span>), <span class="title function_">catchError</span>(<span class="variable language_">this</span>.<span class="property">handleError</span>))</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public <span class="title function_">postForm</span>(<span class="params">url: string, data: object</span>) &#123;</span><br><span class="line">        <span class="keyword">let</span> <span class="attr">formData</span>: <span class="title class_">FormData</span> = <span class="keyword">new</span> <span class="title class_">FormData</span>()</span><br><span class="line">        formData.<span class="title function_">append</span>(<span class="string">&#x27;username&#x27;</span>, data.<span class="property">username</span>)</span><br><span class="line">        formData.<span class="title function_">append</span>(<span class="string">&#x27;password&#x27;</span>, data.<span class="property">password</span>)</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">post</span>(url, formData)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    private <span class="title function_">extractData</span>(<span class="params">response: Response</span>) &#123;</span><br><span class="line">        <span class="keyword">let</span> res = response.<span class="title function_">json</span>()</span><br><span class="line">        <span class="keyword">return</span> res || &#123;&#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    private <span class="title function_">handleError</span>(<span class="params">error: Response | any</span>) &#123;</span><br><span class="line">        <span class="keyword">let</span> <span class="attr">errMsg</span>: string;</span><br><span class="line">        <span class="keyword">if</span> (error <span class="keyword">instanceof</span> <span class="title class_">Response</span>) &#123;</span><br><span class="line">            <span class="keyword">const</span> data = error.<span class="title function_">json</span>() || <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">            <span class="keyword">const</span> err = data.<span class="property">toString</span> || <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(data);</span><br><span class="line">            errMsg = <span class="string">`<span class="subst">$&#123;error.status&#125;</span> - <span class="subst">$&#123;error.statusText || <span class="string">&#x27;&#x27;</span>&#125;</span> <span class="subst">$&#123;err&#125;</span>`</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            errMsg = error.<span class="property">message</span> ? error.<span class="property">message</span> : error.<span class="title function_">toString</span>();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="title class_">Observable</span>.<span class="keyword">throw</span>(errMsg);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// hero.component.ts</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">HomeComponent</span> implements <span class="title class_">OnInit</span> &#123;</span><br><span class="line">    private <span class="attr">heroes</span>: <span class="title class_">Hero</span>[] = [];</span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params">private heroService: HeroService</span>) &#123; &#125;</span><br><span class="line">    <span class="title function_">getHeroes</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">heroes</span> = <span class="variable language_">this</span>.<span class="property">heroService</span>.<span class="title function_">getHeroes</span>();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


<h2 id="RxJS-编程"><a href="#RxJS-编程" class="headerlink" title="RxJS 编程"></a>RxJS 编程</h2><blockquote>
<p>基于微软 ReactiveX 响应式编程理念来实现异步编程的 JS 工具库，常用的异步编程范式有回调函数、事件监听、发布订阅、Promise、async&#x2F;await、RxJS。响应式编程是一种面向数据流和变更传播的异步编程范式，它将普通数据、http 请求、dom 事件等都包装成流并监听到更新后执行操作，流可看作是数据基于事件变化的整体(流 &#x3D; 数据 + 事件)，它是不可改变的但可以通过通过操作符转换或合并为一个新流并返回。核心概念主要如下：</p>
</blockquote>
<ul>
<li><strong>Observable</strong>：可观察对象，随时间产生的数据集合而可看作异步流，subscribe 启动流。</li>
<li><strong>Observer</strong>：观察者，回调函数的集合，监听 Observable 数据并执行相应操作。</li>
<li><strong>Subscription</strong>：订阅，存储已经启动过的流，unsubscribe 停止该流。</li>
<li><strong>Operators</strong>：操作符，函数式编程风格的纯函数，将异步代码以声明式的方式组合处理。</li>
<li><strong>Subject</strong>：主体，一种特殊类型的 Observable，用于通过多播模式将数据共享给多个观察者。不同于单播订阅者总是需要从头开始获取数据，多播模式能够保证数据的实时性。</li>
<li><strong>Schedulers</strong>：调度器，用来控制何时启动 subscription 和何时发送通知。</li>
</ul>
  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 创建流</span></span><br><span class="line"><span class="keyword">const</span> <span class="title class_">Rx</span> = <span class="built_in">require</span>(<span class="string">&#x27;rxjs/Rx&#x27;</span>)</span><br><span class="line"><span class="keyword">let</span> observable = <span class="title class_">Rx</span>.<span class="property">Observable</span>.<span class="title function_">of</span>(<span class="number">1</span>)/.<span class="title function_">from</span>([<span class="number">2</span>])/.<span class="title function_">interval</span>(<span class="number">3</span>)</span><br><span class="line"><span class="keyword">const</span> stream = <span class="title class_">Rx</span>.<span class="property">Observable</span>.<span class="title function_">create</span>(<span class="function"><span class="params">observer</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">let</span> i = <span class="number">0</span></span><br><span class="line">    <span class="built_in">setInterval</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">        i++;</span><br><span class="line">        <span class="keyword">switch</span> (i) &#123;</span><br><span class="line">            <span class="keyword">case</span> <span class="number">10</span>:</span><br><span class="line">                observer.<span class="title function_">complete</span>();</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="number">11</span>:</span><br><span class="line">                observer.<span class="title function_">error</span>(<span class="string">&#x27;不会执行&#x27;</span>);</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="attr">default</span>:</span><br><span class="line">                observer.<span class="title function_">next</span>(i);</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;, <span class="number">1000</span>)</span><br><span class="line">&#125;)</span><br><span class="line"><span class="comment">// 启动流：订阅后才会执行 next()</span></span><br><span class="line"><span class="keyword">const</span> subscription = stream.<span class="title function_">subscribe</span>(<span class="function"><span class="params">val</span> =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(val) )</span><br><span class="line"><span class="keyword">const</span> subscription = stream.<span class="title function_">subscribe</span>(&#123;</span><br><span class="line">    <span class="attr">next</span>: <span class="function"><span class="params">val</span> =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(val),</span><br><span class="line">    <span class="attr">error</span>: <span class="function"><span class="params">err</span> =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(err),</span><br><span class="line">    <span class="attr">complete</span>: <span class="function">() =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;finish&quot;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"><span class="comment">// 关闭流：取消订阅</span></span><br><span class="line"><span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123; subscription.<span class="title function_">unsubscribe</span>() &#125;, <span class="number">1000</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> subject：多播，以下为其三个变体</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> BehaviorSubject：有新订阅时会额外发出最新值</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> BehaviorSubject：保存所有值，然后回放给新的订阅者</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> AsyncSubject：只有 Observable 执行完成时才会发出最后的值</span></span><br><span class="line"><span class="comment"> */</span> </span><br><span class="line"><span class="keyword">const</span> source = <span class="title class_">Rx</span>.<span class="property">Observable</span>.<span class="title function_">interval</span>(<span class="number">1000</span>).<span class="title function_">pipe</span>(<span class="title function_">take</span>(<span class="number">3</span>))</span><br><span class="line"><span class="keyword">const</span> subject = <span class="keyword">new</span> <span class="title class_">Rx</span>.<span class="property">Subject</span>&lt;number&gt;()</span><br><span class="line"><span class="keyword">const</span> subject = <span class="keyword">new</span> <span class="title class_">Rx</span>.<span class="title class_">BehaviorSubject</span>(<span class="number">0</span>)</span><br><span class="line"><span class="keyword">const</span> subject = <span class="keyword">new</span> <span class="title class_">Rx</span>.<span class="title class_">ReplaySubject</span>(<span class="number">2</span>);</span><br><span class="line"><span class="keyword">const</span> subject = <span class="keyword">new</span> <span class="title class_">Rx</span>.<span class="title class_">AsyncSubject</span>()</span><br><span class="line">subject.<span class="title function_">subscribe</span>(<span class="function">(<span class="params">value: number</span>) =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;A：&#x27;</span> + value))</span><br><span class="line">subject.<span class="title function_">subscribe</span>(<span class="function">(<span class="params">value: number</span>) =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;B：&#x27;</span> + value))</span><br><span class="line">subject.<span class="title function_">next</span>(<span class="number">1</span>)</span><br><span class="line">subject.<span class="title function_">next</span>(<span class="number">2</span>)</span><br><span class="line">source.<span class="title function_">subscribe</span>(subject)  <span class="comment">// 注释掉就不会执行</span></span><br><span class="line"> </span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span>  Schedulers 调度器</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prames</span> null：不传递调度器，以同步方式发送通知，用于定时或尾递归操作。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prames</span> Rx.Scheduler.queue：当前事件帧中的队列调度，用于迭代操作。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prames</span> Rx.Scheduler.asap：微任务的队列调度，用于异步转换。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prames</span> Rx.Scheduler.async：setInterval 调度，用于基于时间的操作符。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> 打印结果：before、after、1、done</span></span><br><span class="line"><span class="comment"> **/</span> </span><br><span class="line"><span class="keyword">var</span> observable = <span class="title class_">Rx</span>.<span class="property">Observable</span>.<span class="title function_">create</span>(<span class="keyword">function</span> (<span class="params">observer</span>) &#123;</span><br><span class="line">    observer.<span class="title function_">next</span>(<span class="number">1</span>);</span><br><span class="line">    observer.<span class="title function_">complete</span>();</span><br><span class="line">&#125;)</span><br><span class="line">.<span class="title function_">observeOn</span>(<span class="title class_">Rx</span>.<span class="property">Scheduler</span>.<span class="property">async</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;before&#x27;</span>);</span><br><span class="line">observable.<span class="title function_">subscribe</span>(&#123;</span><br><span class="line">  <span class="attr">next</span>: <span class="function"><span class="params">x</span> =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(x),</span><br><span class="line">  <span class="attr">complete</span>: <span class="function">() =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;done&#x27;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;after&#x27;</span>);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> Operators 常用操作符</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> 创建类：create、from、fromEvent、fromPromise、of、range、interval</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> 合并类：concat、merge、zip、race、startWith、forkJoin、switch</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@prame</span> 转化类：map、scan、concatMap、mergeMap、switchMap、exhaustMap</span></span><br><span class="line"><span class="comment"> **/</span></span><br><span class="line"><span class="keyword">import</span> &#123;fromEvent, <span class="title class_">Observable</span>, <span class="keyword">of</span>, throwError&#125; <span class="keyword">from</span> <span class="string">&#x27;rxjs&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123;catchError, debounceTime, pluck, switchMap&#125; <span class="keyword">from</span> <span class="string">&#x27;rxjs/operators&#x27;</span>;</span><br><span class="line"><span class="keyword">var</span> stream = <span class="title function_">fromEvent</span>(input, <span class="string">&#x27;keyup&#x27;</span>).<span class="title function_">pipe</span>(  <span class="comment">// 创建事件流</span></span><br><span class="line">                <span class="title function_">debounceTime</span>(<span class="number">500</span>),            <span class="comment">// 防抖动：忽略 0.5s 间隔内的输入</span></span><br><span class="line">                <span class="title function_">pluck</span>(<span class="string">&#x27;target&#x27;</span>, <span class="string">&#x27;value&#x27;</span>),     <span class="comment">// 获取输入值</span></span><br><span class="line">                <span class="comment">// 输入流转 http：每一次请求前先取消上一次的请求</span></span><br><span class="line">                .<span class="title function_">switchMap</span>(<span class="function"><span class="params">value</span> =&gt;</span> value.<span class="property">length</span> ? <span class="title function_">httpInput</span>(value) : <span class="title function_">of</span>([])),</span><br><span class="line">                <span class="title function_">catchError</span>(<span class="function"><span class="params">err</span> =&gt;</span> <span class="title function_">throwError</span>(err))</span><br><span class="line">             )</span><br><span class="line">             .<span class="title function_">subscribe</span>(</span><br><span class="line">                <span class="function"><span class="params">res</span> =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">log</span>(res),</span><br><span class="line">                <span class="function"><span class="params">error</span> =&gt;</span> <span class="variable language_">console</span>.<span class="title function_">error</span>(error)</span><br><span class="line">             )</span><br></pre></td></tr></table></figure>

<h2 id="http-拦截器"><a href="#http-拦截器" class="headerlink" title="http 拦截器"></a>http 拦截器</h2>  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// ngModule 引入拦截器</span></span><br><span class="line">@<span class="title class_">NgModule</span>(&#123;</span><br><span class="line">    <span class="attr">providers</span>: [&#123; </span><br><span class="line">        <span class="attr">provide</span>: <span class="variable constant_">HTTP_INTERCEPTORS</span>, <span class="attr">useClass</span>: <span class="title class_">ParamInterceptor</span>, <span class="attr">multi</span>: <span class="literal">true</span> </span><br><span class="line">    &#125;]</span><br><span class="line">&#125;)</span><br><span class="line"><span class="comment">// 拦截器自定义：ng g interceptor xxx</span></span><br><span class="line">@<span class="title class_">Injectable</span>()</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">ParamInterceptor</span> implements <span class="title class_">HttpInterceptor</span> &#123;</span><br><span class="line">    <span class="title function_">intercept</span>(<span class="params">req: HttpRequest&lt;any&gt;, next: HttpHandler</span>) &#123;</span><br><span class="line">        <span class="comment">// HttpRequest、HttpResponse 实例的属性是只读的，所以需要克隆后回传</span></span><br><span class="line">        <span class="keyword">const</span> authReq = req.<span class="title function_">clone</span>(&#123;</span><br><span class="line">            <span class="attr">setHeaders</span>: &#123; <span class="attr">token</span>: req.<span class="property">headers</span>.<span class="title function_">get</span>(<span class="string">&#x27;Authorization&#x27;</span>) || <span class="string">&#x27;123&#x27;</span> &#125;</span><br><span class="line">        &#125;)</span><br><span class="line">        <span class="keyword">return</span> next.<span class="title function_">handle</span>(authReq);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 封装拦截器</span></span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">Injectable</span>, <span class="title class_">Injector</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;@angular/core&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">Router</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;@angular/router&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123;</span><br><span class="line">    <span class="title class_">HttpInterceptor</span>,</span><br><span class="line">    <span class="title class_">HttpRequest</span>,</span><br><span class="line">    <span class="title class_">HttpHandler</span>,</span><br><span class="line">    <span class="title class_">HttpErrorResponse</span>,</span><br><span class="line">    <span class="title class_">HttpResponse</span>,</span><br><span class="line">    <span class="title class_">HttpEvent</span>,</span><br><span class="line">    <span class="title class_">HttpResponseBase</span></span><br><span class="line">&#125; <span class="keyword">from</span> <span class="string">&#x27;@angular/common/http&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">Observable</span>, <span class="keyword">of</span>, throwError &#125; <span class="keyword">from</span> <span class="string">&#x27;rxjs&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; mergeMap, catchError &#125; <span class="keyword">from</span> <span class="string">&#x27;rxjs/operators&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> <span class="variable constant_">CODEMESSAGE</span> = &#123;</span><br><span class="line">  <span class="number">200</span>: <span class="string">&#x27;服务器成功返回请求的数据。&#x27;</span>,</span><br><span class="line">  <span class="number">201</span>: <span class="string">&#x27;新建或修改数据成功。&#x27;</span>,</span><br><span class="line">  <span class="number">202</span>: <span class="string">&#x27;一个请求已经进入后台排队（异步任务）。&#x27;</span>,</span><br><span class="line">  <span class="number">204</span>: <span class="string">&#x27;删除数据成功。&#x27;</span>,</span><br><span class="line">  <span class="number">400</span>: <span class="string">&#x27;发出的请求有错误，服务器没有进行新建或修改数据的操作。&#x27;</span>,</span><br><span class="line">  <span class="number">401</span>: <span class="string">&#x27;用户没有权限（令牌、用户名、密码错误）。&#x27;</span>,</span><br><span class="line">  <span class="number">403</span>: <span class="string">&#x27;用户得到授权，但是访问是被禁止的。&#x27;</span>,</span><br><span class="line">  <span class="number">404</span>: <span class="string">&#x27;发出的请求针对的是不存在的记录，服务器没有进行操作。&#x27;</span>,</span><br><span class="line">  <span class="number">406</span>: <span class="string">&#x27;请求的格式不可得。&#x27;</span>,</span><br><span class="line">  <span class="number">410</span>: <span class="string">&#x27;请求的资源被永久删除，且不会再得到的。&#x27;</span>,</span><br><span class="line">  <span class="number">422</span>: <span class="string">&#x27;当创建一个对象时，发生一个验证错误。&#x27;</span>,</span><br><span class="line">  <span class="number">500</span>: <span class="string">&#x27;服务器发生错误，请检查服务器。&#x27;</span>,</span><br><span class="line">  <span class="number">502</span>: <span class="string">&#x27;网关错误。&#x27;</span>,</span><br><span class="line">  <span class="number">503</span>: <span class="string">&#x27;服务不可用，服务器暂时过载或维护。&#x27;</span>,</span><br><span class="line">  <span class="number">504</span>: <span class="string">&#x27;网关超时。&#x27;</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">@<span class="title class_">Injectable</span>()</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">DefaultInterceptor</span> implements <span class="title class_">HttpInterceptor</span> &#123;</span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params">private injector: Injector</span>) &#123;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">get</span> <span class="title function_">msg</span>(): <span class="title class_">NzMessageService</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">injector</span>.<span class="title function_">get</span>(<span class="title class_">NzMessageService</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    private <span class="title function_">goTo</span>(<span class="params">url: string</span>) &#123;</span><br><span class="line">        <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> <span class="variable language_">this</span>.<span class="property">injector</span>.<span class="title function_">get</span>(<span class="title class_">Router</span>).<span class="title function_">navigateByUrl</span>(url));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    private <span class="title function_">checkStatus</span>(<span class="params">ev: HttpResponseBase</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (ev.<span class="property">status</span> &gt;= <span class="number">200</span> &amp;&amp; ev.<span class="property">status</span> &lt; <span class="number">300</span>) &#123; <span class="keyword">return</span> &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">const</span> errortext = <span class="variable constant_">CODEMESSAGE</span>[ev.<span class="property">status</span>] || ev.<span class="property">statusText</span>;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">injector</span>.<span class="title function_">get</span>(<span class="title class_">NzNotificationService</span>)</span><br><span class="line">                     .<span class="title function_">error</span>(<span class="string">`请求错误 <span class="subst">$&#123;ev.status&#125;</span>: <span class="subst">$&#123;ev.url&#125;</span>`</span>, errortext);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    private <span class="title function_">handleData</span>(<span class="attr">ev</span>: <span class="title class_">HttpResponseBase</span>): <span class="title class_">Observable</span>&lt;any&gt; &#123;</span><br><span class="line">        <span class="comment">// 可能会因为 throw 导出无法执行 _HttpClient end() 操作</span></span><br><span class="line">        <span class="keyword">if</span> (ev.<span class="property">status</span> &gt; <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">injector</span>.<span class="title function_">get</span>(_HttpClient).<span class="title function_">end</span>();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="title function_">checkStatus</span>(ev);</span><br><span class="line">        <span class="comment">// 业务处理：一些通用操作</span></span><br><span class="line">        <span class="keyword">switch</span> (ev.<span class="property">status</span>) &#123;</span><br><span class="line">            <span class="keyword">case</span> <span class="number">200</span>:</span><br><span class="line">                <span class="comment">// 业务层级错误处理，比如响应内容 &#123; status: 0, response: &#123;&#125; &#125;</span></span><br><span class="line">                <span class="keyword">if</span> (event <span class="keyword">instanceof</span> <span class="title class_">HttpResponse</span>) &#123;</span><br><span class="line">                    <span class="keyword">const</span> <span class="attr">body</span>: any = event.<span class="property">body</span>;</span><br><span class="line">                    <span class="keyword">if</span> (body &amp;&amp; body.<span class="property">status</span> !== <span class="number">0</span>) &#123;</span><br><span class="line">                        <span class="variable language_">this</span>.<span class="property">msg</span>.<span class="title function_">error</span>(body.<span class="property">msg</span>);</span><br><span class="line">                        <span class="keyword">return</span> <span class="title function_">throwError</span>(&#123;&#125;);</span><br><span class="line">                    &#125;</span><br><span class="line">                    <span class="comment">// 重新修改 body 内容为 response 内容</span></span><br><span class="line">                    <span class="keyword">let</span> _event = <span class="title class_">Object</span>.<span class="title function_">assign</span>(event, &#123;<span class="attr">body</span>: body.<span class="property">response</span>&#125;) </span><br><span class="line">                    <span class="keyword">return</span> <span class="title function_">of</span>(<span class="keyword">new</span> <span class="title class_">HttpResponse</span>(_event));</span><br><span class="line">                    <span class="comment">// 或者依然保持完整格式</span></span><br><span class="line">                    <span class="keyword">return</span> <span class="title function_">of</span>(event);</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="number">401</span>: <span class="comment">// 请求错误 401: 用户没有权限（令牌、用户名、密码错误）</span></span><br><span class="line">                <span class="variable language_">this</span>.<span class="title function_">goTo</span>(<span class="string">&#x27;/passport/login?clean=token&#x27;</span>);</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="number">403</span>:</span><br><span class="line">            <span class="keyword">case</span> <span class="number">404</span>:</span><br><span class="line">            <span class="keyword">case</span> <span class="number">500</span>:</span><br><span class="line">                <span class="variable language_">this</span>.<span class="title function_">goTo</span>(<span class="string">`/exception/<span class="subst">$&#123;ev.status&#125;</span>`</span>);</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="attr">default</span>:</span><br><span class="line">                <span class="keyword">if</span> (ev <span class="keyword">instanceof</span> <span class="title class_">HttpErrorResponse</span>) &#123;</span><br><span class="line">                  <span class="variable language_">console</span>.<span class="title function_">warn</span>(<span class="string">&#x27;未可知错误&#x27;</span>, ev);</span><br><span class="line">                  <span class="variable language_">this</span>.<span class="property">msg</span>.<span class="title function_">error</span>(ev.<span class="property">message</span>);</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">of</span>(ev);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="title function_">intercept</span>(<span class="attr">req</span>: <span class="title class_">HttpRequest</span>, <span class="attr">next</span>: <span class="title class_">HttpHandler</span>): <span class="title class_">Observable</span>&lt;<span class="title class_">HttpEvent</span>&gt; &#123;</span><br><span class="line">        <span class="comment">// 统一加上服务端前缀</span></span><br><span class="line">        <span class="keyword">let</span> url = req.<span class="property">url</span>;</span><br><span class="line">        <span class="keyword">if</span> (!url.<span class="title function_">startsWith</span>(<span class="string">&#x27;https://&#x27;</span>) &amp;&amp; !url.<span class="title function_">startsWith</span>(<span class="string">&#x27;http://&#x27;</span>)) &#123;</span><br><span class="line">            url = environment.<span class="property">SERVER_URL</span> + url;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">const</span> newReq = req.<span class="title function_">clone</span>(&#123; url &#125;);</span><br><span class="line">        <span class="keyword">return</span> next.<span class="title function_">handle</span>(newReq).<span class="title function_">pipe</span>(</span><br><span class="line">            <span class="title function_">mergeMap</span>(<span class="function">(<span class="params">event: any</span>) =&gt;</span> &#123;</span><br><span class="line">                <span class="comment">// 允许统一对请求错误处理</span></span><br><span class="line">                <span class="keyword">if</span> (event <span class="keyword">instanceof</span> <span class="title class_">HttpResponseBase</span>) &#123;</span><br><span class="line">                    <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">handleData</span>(event);</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="comment">// 若一切都正常，则后续操作</span></span><br><span class="line">                <span class="keyword">return</span> <span class="title function_">of</span>(event);</span><br><span class="line">            &#125;),</span><br><span class="line">            <span class="title function_">catchError</span>(<span class="function">(<span class="params">err: HttpErrorResponse</span>) =&gt;</span> <span class="variable language_">this</span>.<span class="title function_">handleData</span>(err))</span><br><span class="line">        )</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure>



<h1 id="五、Router-路由"><a href="#五、Router-路由" class="headerlink" title="五、Router 路由"></a>五、Router 路由</h1>
    </div>

    
    
    <div>
      
        <div>
    
        <div style="text-align:center;color: #ccc;font-size:14px;margin-top:20px;">-------------本文结束<i class="fa fa-paw"></i>感谢您的阅读-------------</div>
    
</div>

      
    </div>
    
        

<div>
<ul class="post-copyright">
  <li class="post-copyright-author">
    <strong>本文作者： </strong>chuangges
  </li>
  <li class="post-copyright-link">
    <strong>本文链接：</strong>
    <a href="https://chuangges.gitee.io/2020/09/09/14-1-angular%E5%9F%BA%E7%A1%80/" title="Angular 项目开发">https://chuangges.gitee.io/2020/09/09/14-1-angular基础/</a>
  </li>
  <li class="post-copyright-license">
    <strong>版权声明： </strong>本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/zh_CN" rel="external nofollow noopener noreferrer" target="_blank"><i class="fab fa-fw fa-creative-commons"></i>BY-NC-SA</a> 许可协议。转载请注明出处！
  </li>
</ul>
</div>


      <footer class="post-footer">

        


        
    <div class="post-nav">
      <div class="post-nav-item">
    <a href="/2020/04/05/13-%E9%9D%A2%E8%AF%95%E9%A2%98%E4%B9%8B%E6%8F%90%E5%8D%87%E7%AF%87/" rel="prev" title="面试题之提升篇">
      <i class="fa fa-chevron-left"></i> 面试题之提升篇
    </a></div>
      <div class="post-nav-item">
    <a href="/2020/11/03/14-2-angular%E7%BB%84%E4%BB%B6%E5%8C%96%E5%BC%80%E5%8F%91/" rel="next" title="Angular 组件化开发">
      Angular 组件化开发 <i class="fa fa-chevron-right"></i>
    </a></div>
    </div>
      </footer>
    
  </article>
  
  
  



          </div>
          

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
          <div class="post-toc motion-element"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%B8%80%E3%80%81%E9%A1%B9%E7%9B%AE%E6%9E%84%E5%BB%BA"><span class="nav-number">1.</span> <span class="nav-text">一、项目构建</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E9%A1%B9%E7%9B%AE%E6%96%B0%E5%BB%BA"><span class="nav-number">1.1.</span> <span class="nav-text">项目新建</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%9B%AE%E5%BD%95%E8%A7%A3%E6%9E%90"><span class="nav-number">1.2.</span> <span class="nav-text">目录解析</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%A8%A1%E5%9D%97%E5%BC%95%E7%94%A8"><span class="nav-number">1.3.</span> <span class="nav-text">模块引用</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%BA%8C%E3%80%81%E7%BB%84%E4%BB%B6%E5%BC%80%E5%8F%91"><span class="nav-number">2.</span> <span class="nav-text">二、组件开发</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%BB%84%E4%BB%B6"><span class="nav-number">2.1.</span> <span class="nav-text">组件</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%A8%A1%E6%9D%BF"><span class="nav-number">2.2.</span> <span class="nav-text">模板</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%8C%87%E4%BB%A4"><span class="nav-number">2.3.</span> <span class="nav-text">指令</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%AE%A1%E9%81%93"><span class="nav-number">2.4.</span> <span class="nav-text">管道</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%9C%8D%E5%8A%A1"><span class="nav-number">2.5.</span> <span class="nav-text">服务</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F"><span class="nav-number">2.6.</span> <span class="nav-text">生命周期</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%BB%84%E4%BB%B6%E9%80%9A%E4%BF%A1"><span class="nav-number">2.7.</span> <span class="nav-text">组件通信</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%B8%89%E3%80%81%E8%A1%A8%E5%8D%95%E6%8E%A7%E4%BB%B6"><span class="nav-number">3.</span> <span class="nav-text">三、表单控件</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%A8%A1%E6%9D%BF%E9%A9%B1%E5%8A%A8%E8%A1%A8%E5%8D%95"><span class="nav-number">3.1.</span> <span class="nav-text">模板驱动表单</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%93%8D%E5%BA%94%E5%BC%8F%E8%A1%A8%E5%8D%95"><span class="nav-number">3.2.</span> <span class="nav-text">响应式表单</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E8%87%AA%E5%AE%9A%E4%B9%89%E9%AA%8C%E8%AF%81"><span class="nav-number">3.3.</span> <span class="nav-text">自定义验证</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E8%B7%A8%E5%AD%97%E6%AE%B5%E9%AA%8C%E8%AF%81"><span class="nav-number">3.4.</span> <span class="nav-text">跨字段验证</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%9B%9B%E3%80%81HTTP-%E8%AF%B7%E6%B1%82"><span class="nav-number">4.</span> <span class="nav-text">四、HTTP 请求</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#http-%E6%9C%8D%E5%8A%A1"><span class="nav-number">4.1.</span> <span class="nav-text">http 服务</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#RxJS-%E7%BC%96%E7%A8%8B"><span class="nav-number">4.2.</span> <span class="nav-text">RxJS 编程</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#http-%E6%8B%A6%E6%88%AA%E5%99%A8"><span class="nav-number">4.3.</span> <span class="nav-text">http 拦截器</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%BA%94%E3%80%81Router-%E8%B7%AF%E7%94%B1"><span class="nav-number">5.</span> <span class="nav-text">五、Router 路由</span></a></li></ol></div>
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="chuangges" src="" data-original="/images/chuang.png">
  <p class="site-author-name" itemprop="name">chuangges</p>
  <div class="site-description" itemprop="description">chuangge's blog.</div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/archives/">
        
          <span class="site-state-item-count">39</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/categories/">
          
        <span class="site-state-item-count">7</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/tags/">
          
        <span class="site-state-item-count">7</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>
  <div class="links-of-author motion-element">
      <span class="links-of-author-item">
        <a href="https://github.com/chuangges" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;chuangges" rel="external nofollow noopener noreferrer" target="_blank"><i class="fab fa-github fa-fw"></i>GitHub</a>
      </span>
      <span class="links-of-author-item">
        <a href="https://stackoverflow.com/yourname" title="StackOverflow → https:&#x2F;&#x2F;stackoverflow.com&#x2F;yourname" rel="external nofollow noopener noreferrer" target="_blank"><i class="fab fa-stack-overflow fa-fw"></i>StackOverflow</a>
      </span>
  </div>


  <div class="links-of-blogroll motion-element">
    <div class="links-of-blogroll-title"><i class="fa fa-link fa-fw"></i>
      友情链接
    </div>
    <ul class="links-of-blogroll-list">
        <li class="links-of-blogroll-item">
          <a href="https://juejin.im/" title="https:&#x2F;&#x2F;juejin.im&#x2F;" rel="external nofollow noopener noreferrer" target="_blank">掘金</a>
        </li>
        <li class="links-of-blogroll-item">
          <a href="https://www.nowcoder.com/" title="https:&#x2F;&#x2F;www.nowcoder.com&#x2F;" rel="external nofollow noopener noreferrer" target="_blank">牛客网</a>
        </li>
        <li class="links-of-blogroll-item">
          <a href="https://www.docschina.org/" title="https:&#x2F;&#x2F;www.docschina.org&#x2F;" rel="external nofollow noopener noreferrer" target="_blank">印记中文</a>
        </li>
        <li class="links-of-blogroll-item">
          <a href="http://tool.lu/" title="http:&#x2F;&#x2F;tool.lu&#x2F;" rel="external nofollow noopener noreferrer" target="_blank">在线工具</a>
        </li>
        <li class="links-of-blogroll-item">
          <a href="https://tinypng.com/" title="https:&#x2F;&#x2F;tinypng.com&#x2F;" rel="external nofollow noopener noreferrer" target="_blank">图片压缩</a>
        </li>
        <li class="links-of-blogroll-item">
          <a href="https://bigjpg.com/" title="https:&#x2F;&#x2F;bigjpg.com&#x2F;" rel="external nofollow noopener noreferrer" target="_blank">图片放大</a>
        </li>
        <li class="links-of-blogroll-item">
          <a href="https://tool.chinaz.com/" title="https:&#x2F;&#x2F;tool.chinaz.com&#x2F;" rel="external nofollow noopener noreferrer" target="_blank">站长工具</a>
        </li>
        <li class="links-of-blogroll-item">
          <a href="https://learn-anything.xyz/" title="https:&#x2F;&#x2F;learn-anything.xyz&#x2F;" rel="external nofollow noopener noreferrer" target="_blank">Learn-Anything</a>
        </li>
        <li class="links-of-blogroll-item">
          <a href="https://stackoverflow.com/" title="https:&#x2F;&#x2F;stackoverflow.com&#x2F;" rel="external nofollow noopener noreferrer" target="_blank">Stack-Overflow</a>
        </li>
    </ul>
  </div>

      </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

        

<div class="copyright">
  
  &copy; 
  <span itemprop="copyrightYear">2024</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">chuangge</span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item-icon">
      <i class="fa fa-chart-area"></i>
    </span>
    <span title="站点总字数">1m</span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item-icon">
      <i class="fa fa-coffee"></i>
    </span>
    <span title="站点阅读时长">15:14</span>
</div>
  <div class="powered-by">由 <a href="https://hexo.io/" class="theme-link" rel="external nofollow noopener noreferrer" target="_blank">Hexo</a> & <a href="https://pisces.theme-next.org/" class="theme-link" rel="external nofollow noopener noreferrer" target="_blank">NexT.Pisces</a> 强力驱动
  </div>

        








      </div>
    </footer>
  </div>

  
  <script src="/lib/anime.min.js"></script>
  <script src="/lib/velocity/velocity.min.js"></script>
  <script src="/lib/velocity/velocity.ui.min.js"></script>

<script src="/js/utils.js"></script>

<script src="/js/motion.js"></script>


<script src="/js/schemes/pisces.js"></script>


<script src="/js/next-boot.js"></script>




  















  

  

<script src="/live2dw/lib/L2Dwidget.min.js?094cbace49a39548bed64abff5988b05"></script><script>L2Dwidget.init({"pluginRootPath":"live2dw/","pluginJsPath":"lib/","pluginModelPath":"assets/","model":{"jsonPath":"/live2dw/assets/tororo.model.json"},"display":{"position":"left","width":180,"height":360},"mobile":{"show":false},"react":{"opacityDefault":1,"opacityOnHover":1},"log":false,"tagMode":false});</script>
        <style>
            [bg-lazy] {
                background-image: none !important;
                background-color: #eee !important;
            }
        </style>
        <script>
            window.imageLazyLoadSetting = {
                isSPA: false,
                preloadRatio: 1,
                processImages: null,
            };
        </script><script>window.addEventListener("load",function(){var t=/\.(gif|jpg|jpeg|tiff|png)$/i,r=/^data:image\/[a-z]+;base64,/;Array.prototype.slice.call(document.querySelectorAll("img[data-original]")).forEach(function(a){var e=a.parentNode;"A"===e.tagName&&(e.href.match(t)||e.href.match(r))&&(e.href=a.dataset.original)})});</script><script>!function(e){e.imageLazyLoadSetting.processImages=t;var n=e.imageLazyLoadSetting.isSPA,i=e.imageLazyLoadSetting.preloadRatio||1,r=o();function o(){var t=Array.prototype.slice.call(document.querySelectorAll("img[data-original]")),e=Array.prototype.slice.call(document.querySelectorAll("[bg-lazy]"));return t.concat(e)}function t(){n&&(r=o());for(var t,a=0;a<r.length;a++)0<=(t=(t=r[a]).getBoundingClientRect()).bottom&&0<=t.left&&t.top<=(e.innerHeight*i||document.documentElement.clientHeight*i)&&function(){var t,e,n,i,o=r[a];e=function(){r=r.filter(function(t){return o!==t})},(t=o).hasAttribute("bg-lazy")?(t.removeAttribute("bg-lazy"),e&&e()):(n=new Image,i=t.getAttribute("data-original"),n.onload=function(){t.src=i,t.removeAttribute("data-original"),e&&e()},t.src!==i&&(n.src=i))}()}function a(){clearTimeout(t.tId),t.tId=setTimeout(t,500)}t(),document.addEventListener("scroll",a),e.addEventListener("resize",a),e.addEventListener("orientationchange",a)}(this);</script></body>
</html>
